back to OpenHands summary
OpenHands: cookiecutter
Pytest Summary for test tests
| status |
count |
| passed |
116 |
| failed |
237 |
| error |
14 |
| skipped |
4 |
| total |
371 |
| collected |
371 |
Failed pytests:
test_dump.py::test_value_error_if_key_missing_in_context
test_dump.py::test_value_error_if_key_missing_in_context
replay_test_dir = 'tests/test-replay/', template_name = 'cookiedozer'
def test_value_error_if_key_missing_in_context(replay_test_dir, template_name):
"""Test that replay.dump raises if the context does not contain a key \
named 'cookiecutter'."""
> with pytest.raises(ValueError):
E Failed: DID NOT RAISE
tests/replay/test_dump.py:50: Failed
test_load.py::test_value_error_if_key_missing_in_context
test_load.py::test_value_error_if_key_missing_in_context
mocker =
replay_test_dir = 'tests/test-replay/'
def test_value_error_if_key_missing_in_context(mocker, replay_test_dir):
"""Test that replay.load raises if the loaded context does not contain \
'cookiecutter'."""
> with pytest.raises(ValueError):
E Failed: DID NOT RAISE
tests/replay/test_load.py:33: Failed
test_replay.py::test_raise_on_invalid_mode[invalid_kwargs1]
test_replay.py::test_raise_on_invalid_mode[invalid_kwargs1]
invalid_kwargs = {'extra_context': {}}
@pytest.mark.parametrize(
'invalid_kwargs',
(
{'no_input': True},
{'extra_context': {}},
{'no_input': True, 'extra_context': {}},
),
)
def test_raise_on_invalid_mode(invalid_kwargs):
"""Test `cookiecutter` raise exception on unacceptable `replay` request."""
with pytest.raises(exceptions.InvalidModeException):
> main.cookiecutter('foo', replay=True, **invalid_kwargs)
tests/replay/test_replay.py:29:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'foo', checkout = None, no_input = False, extra_context = {}
replay = True, overwrite_if_exists = False, output_dir = '.', config_file = None
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_replay.py::test_main_does_not_invoke_dump_but_load
test_replay.py::test_main_does_not_invoke_dump_but_load
mocker =
def test_main_does_not_invoke_dump_but_load(mocker):
"""Test `cookiecutter` calling correct functions on `replay`."""
mock_prompt = mocker.patch('cookiecutter.main.prompt_for_config')
mock_gen_context = mocker.patch('cookiecutter.main.generate_context')
mock_gen_files = mocker.patch('cookiecutter.main.generate_files')
mock_replay_dump = mocker.patch('cookiecutter.main.dump')
mock_replay_load = mocker.patch('cookiecutter.main.load')
> main.cookiecutter('tests/fake-repo-tmpl/', replay=True)
tests/replay/test_replay.py:40:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-tmpl/', checkout = None, no_input = False
extra_context = None, replay = True, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_replay.py::test_main_does_not_invoke_load_but_dump
test_replay.py::test_main_does_not_invoke_load_but_dump
mocker =
def test_main_does_not_invoke_load_but_dump(mocker):
"""Test `cookiecutter` calling correct functions on non-replay launch."""
mock_prompt = mocker.patch('cookiecutter.main.prompt_for_config')
mock_gen_context = mocker.patch('cookiecutter.main.generate_context')
mock_gen_files = mocker.patch('cookiecutter.main.generate_files')
mock_replay_dump = mocker.patch('cookiecutter.main.dump')
mock_replay_load = mocker.patch('cookiecutter.main.load')
> main.cookiecutter('tests/fake-repo-tmpl/', replay=False)
tests/replay/test_replay.py:57:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-tmpl/', checkout = None, no_input = False
extra_context = None, replay = False, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_abbreviation_expansion.py::test_abbreviation_expansion[Simple expansion]
test_abbreviation_expansion.py::test_abbreviation_expansion[Simple expansion]
template = 'foo', abbreviations = {'foo': 'bar'}, expected_result = 'bar'
@pytest.mark.parametrize(
('template', 'abbreviations', 'expected_result'),
[
('foo', {'foo': 'bar'}, 'bar'),
('baz', {'foo': 'bar'}, 'baz'),
('xx:a', {'xx': '<{0}>'}, ''),
('gh:a', {'gh': '<{0}>'}, ''),
('xx:a', {'xx': '<>'}, '<>'),
(
'gh:pydanny/cookiecutter-django',
BUILTIN_ABBREVIATIONS,
'https://github.com/pydanny/cookiecutter-django.git',
),
(
'gl:pydanny/cookiecutter-django',
BUILTIN_ABBREVIATIONS,
'https://gitlab.com/pydanny/cookiecutter-django.git',
),
(
'bb:pydanny/cookiecutter-django',
BUILTIN_ABBREVIATIONS,
'https://bitbucket.org/pydanny/cookiecutter-django',
),
],
ids=(
'Simple expansion',
'Skip expansion (expansion not an abbreviation)',
'Expansion prefix',
'expansion_override_builtin',
'expansion_prefix_ignores_suffix',
'Correct expansion for builtin abbreviations (github)',
'Correct expansion for builtin abbreviations (gitlab)',
'Correct expansion for builtin abbreviations (bitbucket)',
),
)
def test_abbreviation_expansion(template, abbreviations, expected_result):
"""Verify abbreviation unpacking."""
expanded = expand_abbreviations(template, abbreviations)
> assert expanded == expected_result
E AssertionError: assert 'foo' == 'bar'
E
E - bar
E + foo
tests/repository/test_abbreviation_expansion.py:47: AssertionError
test_determine_repo_dir_clones_repo.py::test_repository_url_should_clone
test_determine_repo_dir_clones_repo.py::test_repository_url_should_clone
mocker =
template_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin.git'
user_config_data = {'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters', 'replay_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutter_replay'}
def test_repository_url_should_clone(mocker, template_url, user_config_data):
"""Verify repository url triggers clone function.
`clone()` should be called with correct args when `determine_repo_dir()` is
passed a repository template url.
"""
mock_clone = mocker.patch(
'cookiecutter.repository.clone',
return_value='tests/fake-repo-tmpl',
autospec=True,
)
project_dir, cleanup = repository.determine_repo_dir(
template_url,
abbreviations={},
clone_to_dir=user_config_data['cookiecutters_dir'],
checkout=None,
no_input=True,
)
mock_clone.assert_called_once_with(
repo_url=template_url,
checkout=None,
clone_to_dir=user_config_data['cookiecutters_dir'],
no_input=True,
)
assert os.path.isdir(project_dir)
> assert not cleanup
E assert not True
tests/repository/test_determine_repo_dir_clones_repo.py:89: AssertionError
test_determine_repo_dir_finds_existing_cookiecutter.py::test_should_find_existing_cookiecutter
test_determine_repo_dir_finds_existing_cookiecutter.py::test_should_find_existing_cookiecutter
template = 'cookiecutter-pytest-plugin'
user_config_data = {'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters', 'replay_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutter_replay'}
cloned_cookiecutter_path = '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters/cookiecutter-pytest-plugin'
def test_should_find_existing_cookiecutter(
template, user_config_data, cloned_cookiecutter_path
):
"""
Should find folder created by `cloned_cookiecutter_path` and return it.
This folder is considered like previously cloned project directory.
"""
> project_dir, cleanup = repository.determine_repo_dir(
template=template,
abbreviations={},
clone_to_dir=user_config_data['cookiecutters_dir'],
checkout=None,
no_input=True,
)
tests/repository/test_determine_repo_dir_finds_existing_cookiecutter.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/repository.py:103: in determine_repo_dir
repo_dir = clone(
cookiecutter/vcs.py:72: in clone
repo_type, repo_url = identify_repo(repo_url)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_url = 'cookiecutter-pytest-plugin'
def identify_repo(repo_url):
"""Determine if `repo_url` should be treated as a URL to a git or hg repo.
Repos can be identified by prepending "hg+" or "git+" to the repo URL.
:param repo_url: Repo URL of unknown type.
:returns: ('git', repo_url), ('hg', repo_url), or None.
:raises: UnknownRepoType if the repo type cannot be determined.
"""
if repo_url.startswith('git+'):
return 'git', repo_url[4:]
elif repo_url.startswith('hg+'):
return 'hg', repo_url[3:]
elif any(host in repo_url for host in ['github.com', 'gitlab.com', 'gitorious.org']):
return 'git', repo_url
elif 'bitbucket.org' in repo_url:
if repo_url.endswith('.git'):
return 'git', repo_url
else:
return 'hg', repo_url
elif repo_url.endswith('.git'):
return 'git', repo_url
elif repo_url.endswith('.hg'):
return 'hg', repo_url
elif '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
return 'git', repo_url
> raise UnknownRepoType
E cookiecutter.exceptions.UnknownRepoType
cookiecutter/vcs.py:41: UnknownRepoType
test_determine_repo_dir_finds_subdirectories.py::test_should_find_existing_cookiecutter
test_determine_repo_dir_finds_subdirectories.py::test_should_find_existing_cookiecutter
template = 'cookiecutter-pytest-plugin'
user_config_data = {'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters', 'replay_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutter_replay'}
cloned_cookiecutter_path = '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters/cookiecutter-pytest-plugin/my-dir'
def test_should_find_existing_cookiecutter(
template, user_config_data, cloned_cookiecutter_path
):
"""Find `cookiecutter.json` in sub folder created by `cloned_cookiecutter_path`."""
> project_dir, cleanup = repository.determine_repo_dir(
template=template,
abbreviations={},
clone_to_dir=user_config_data['cookiecutters_dir'],
checkout=None,
no_input=True,
directory='my-dir',
)
tests/repository/test_determine_repo_dir_finds_subdirectories.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/repository.py:103: in determine_repo_dir
repo_dir = clone(
cookiecutter/vcs.py:72: in clone
repo_type, repo_url = identify_repo(repo_url)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_url = 'cookiecutter-pytest-plugin'
def identify_repo(repo_url):
"""Determine if `repo_url` should be treated as a URL to a git or hg repo.
Repos can be identified by prepending "hg+" or "git+" to the repo URL.
:param repo_url: Repo URL of unknown type.
:returns: ('git', repo_url), ('hg', repo_url), or None.
:raises: UnknownRepoType if the repo type cannot be determined.
"""
if repo_url.startswith('git+'):
return 'git', repo_url[4:]
elif repo_url.startswith('hg+'):
return 'hg', repo_url[3:]
elif any(host in repo_url for host in ['github.com', 'gitlab.com', 'gitorious.org']):
return 'git', repo_url
elif 'bitbucket.org' in repo_url:
if repo_url.endswith('.git'):
return 'git', repo_url
else:
return 'hg', repo_url
elif repo_url.endswith('.git'):
return 'git', repo_url
elif repo_url.endswith('.hg'):
return 'hg', repo_url
elif '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
return 'git', repo_url
> raise UnknownRepoType
E cookiecutter.exceptions.UnknownRepoType
cookiecutter/vcs.py:41: UnknownRepoType
test_determine_repo_dir_finds_subdirectories.py::test_local_repo_typo
test_determine_repo_dir_finds_subdirectories.py::test_local_repo_typo
template = 'cookiecutter-pytest-plugin'
user_config_data = {'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters', 'replay_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutter_replay'}
cloned_cookiecutter_path = '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters/cookiecutter-pytest-plugin/my-dir'
def test_local_repo_typo(template, user_config_data, cloned_cookiecutter_path):
"""Wrong pointing to `cookiecutter.json` sub-directory should raise."""
with pytest.raises(exceptions.RepositoryNotFound) as err:
> repository.determine_repo_dir(
template=template,
abbreviations={},
clone_to_dir=user_config_data['cookiecutters_dir'],
checkout=None,
no_input=True,
directory='wrong-dir',
)
tests/repository/test_determine_repo_dir_finds_subdirectories.py:54:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/repository.py:103: in determine_repo_dir
repo_dir = clone(
cookiecutter/vcs.py:72: in clone
repo_type, repo_url = identify_repo(repo_url)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_url = 'cookiecutter-pytest-plugin'
def identify_repo(repo_url):
"""Determine if `repo_url` should be treated as a URL to a git or hg repo.
Repos can be identified by prepending "hg+" or "git+" to the repo URL.
:param repo_url: Repo URL of unknown type.
:returns: ('git', repo_url), ('hg', repo_url), or None.
:raises: UnknownRepoType if the repo type cannot be determined.
"""
if repo_url.startswith('git+'):
return 'git', repo_url[4:]
elif repo_url.startswith('hg+'):
return 'hg', repo_url[3:]
elif any(host in repo_url for host in ['github.com', 'gitlab.com', 'gitorious.org']):
return 'git', repo_url
elif 'bitbucket.org' in repo_url:
if repo_url.endswith('.git'):
return 'git', repo_url
else:
return 'hg', repo_url
elif repo_url.endswith('.git'):
return 'git', repo_url
elif repo_url.endswith('.hg'):
return 'hg', repo_url
elif '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
return 'git', repo_url
> raise UnknownRepoType
E cookiecutter.exceptions.UnknownRepoType
cookiecutter/vcs.py:41: UnknownRepoType
test_determine_repository_should_use_local_repo.py::test_local_repo_with_no_context_raises
test_determine_repository_should_use_local_repo.py::test_local_repo_with_no_context_raises
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_local_repo_with_no_contex0')
def test_local_repo_with_no_context_raises(tmp_path):
"""A local repository without a cookiecutter.json should raise a \
`RepositoryNotFound` exception."""
template_path = str(Path('tests', 'fake-repo-bad'))
with pytest.raises(exceptions.RepositoryNotFound) as err:
> repository.determine_repo_dir(
template_path,
abbreviations={},
clone_to_dir=str(tmp_path),
checkout=None,
no_input=True,
)
tests/repository/test_determine_repository_should_use_local_repo.py:29:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/repository.py:103: in determine_repo_dir
repo_dir = clone(
cookiecutter/vcs.py:72: in clone
repo_type, repo_url = identify_repo(repo_url)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_url = 'tests/fake-repo-bad'
def identify_repo(repo_url):
"""Determine if `repo_url` should be treated as a URL to a git or hg repo.
Repos can be identified by prepending "hg+" or "git+" to the repo URL.
:param repo_url: Repo URL of unknown type.
:returns: ('git', repo_url), ('hg', repo_url), or None.
:raises: UnknownRepoType if the repo type cannot be determined.
"""
if repo_url.startswith('git+'):
return 'git', repo_url[4:]
elif repo_url.startswith('hg+'):
return 'hg', repo_url[3:]
elif any(host in repo_url for host in ['github.com', 'gitlab.com', 'gitorious.org']):
return 'git', repo_url
elif 'bitbucket.org' in repo_url:
if repo_url.endswith('.git'):
return 'git', repo_url
else:
return 'hg', repo_url
elif repo_url.endswith('.git'):
return 'git', repo_url
elif repo_url.endswith('.hg'):
return 'hg', repo_url
elif '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
return 'git', repo_url
> raise UnknownRepoType
E cookiecutter.exceptions.UnknownRepoType
cookiecutter/vcs.py:41: UnknownRepoType
test_determine_repository_should_use_local_repo.py::test_local_repo_typo
test_determine_repository_should_use_local_repo.py::test_local_repo_typo
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_local_repo_typo1')
def test_local_repo_typo(tmp_path):
"""An unknown local repository should raise a `RepositoryNotFound` \
exception."""
template_path = str(Path('tests', 'unknown-repo'))
with pytest.raises(exceptions.RepositoryNotFound) as err:
> repository.determine_repo_dir(
template_path,
abbreviations={},
clone_to_dir=str(tmp_path),
checkout=None,
no_input=True,
)
tests/repository/test_determine_repository_should_use_local_repo.py:53:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/repository.py:103: in determine_repo_dir
repo_dir = clone(
cookiecutter/vcs.py:72: in clone
repo_type, repo_url = identify_repo(repo_url)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_url = 'tests/unknown-repo'
def identify_repo(repo_url):
"""Determine if `repo_url` should be treated as a URL to a git or hg repo.
Repos can be identified by prepending "hg+" or "git+" to the repo URL.
:param repo_url: Repo URL of unknown type.
:returns: ('git', repo_url), ('hg', repo_url), or None.
:raises: UnknownRepoType if the repo type cannot be determined.
"""
if repo_url.startswith('git+'):
return 'git', repo_url[4:]
elif repo_url.startswith('hg+'):
return 'hg', repo_url[3:]
elif any(host in repo_url for host in ['github.com', 'gitlab.com', 'gitorious.org']):
return 'git', repo_url
elif 'bitbucket.org' in repo_url:
if repo_url.endswith('.git'):
return 'git', repo_url
else:
return 'hg', repo_url
elif repo_url.endswith('.git'):
return 'git', repo_url
elif repo_url.endswith('.hg'):
return 'hg', repo_url
elif '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
return 'git', repo_url
> raise UnknownRepoType
E cookiecutter.exceptions.UnknownRepoType
cookiecutter/vcs.py:41: UnknownRepoType
test_abort_generate_on_hook_error.py::test_hooks_raises_errors[pre_gen_hook_raises_error]
test_abort_generate_on_hook_error.py::test_hooks_raises_errors[pre_gen_hook_raises_error]
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_hooks_raises_errors_pre_g0')
abort_pre_gen = 'yes', abort_post_gen = 'no'
@pytest.mark.parametrize(
("abort_pre_gen", "abort_post_gen"),
(("yes", "no"), ("no", "yes")),
ids=("pre_gen_hook_raises_error", "post_gen_hook_raises_error"),
)
@pytest.mark.usefixtures("clean_system")
def test_hooks_raises_errors(tmp_path, abort_pre_gen, abort_post_gen):
"""Verify pre- and pos-gen errors raises correct error code from script.
This allows developers to make different error codes in their code,
for different errors.
"""
context = {
"cookiecutter": {
"repo_dir": "foobar",
"abort_pre_gen": abort_pre_gen,
"abort_post_gen": abort_post_gen,
}
}
with pytest.raises(exceptions.FailedHookException) as error:
> generate.generate_files(
repo_dir="tests/hooks-abort-render",
context=context,
output_dir=str(tmp_path),
)
tests/test_abort_generate_on_hook_error.py:34:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/hooks-abort-render'
context = {'cookiecutter': {'abort_post_gen': 'no', 'abort_pre_gen': 'yes', 'repo_dir': 'foobar'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_hooks_raises_errors_pre_g0'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_abort_generate_on_hook_error.py::test_hooks_raises_errors[post_gen_hook_raises_error]
test_abort_generate_on_hook_error.py::test_hooks_raises_errors[post_gen_hook_raises_error]
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_hooks_raises_errors_post_0')
abort_pre_gen = 'no', abort_post_gen = 'yes'
@pytest.mark.parametrize(
("abort_pre_gen", "abort_post_gen"),
(("yes", "no"), ("no", "yes")),
ids=("pre_gen_hook_raises_error", "post_gen_hook_raises_error"),
)
@pytest.mark.usefixtures("clean_system")
def test_hooks_raises_errors(tmp_path, abort_pre_gen, abort_post_gen):
"""Verify pre- and pos-gen errors raises correct error code from script.
This allows developers to make different error codes in their code,
for different errors.
"""
context = {
"cookiecutter": {
"repo_dir": "foobar",
"abort_pre_gen": abort_pre_gen,
"abort_post_gen": abort_post_gen,
}
}
with pytest.raises(exceptions.FailedHookException) as error:
> generate.generate_files(
repo_dir="tests/hooks-abort-render",
context=context,
output_dir=str(tmp_path),
)
tests/test_abort_generate_on_hook_error.py:34:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/hooks-abort-render'
context = {'cookiecutter': {'abort_post_gen': 'yes', 'abort_pre_gen': 'no', 'repo_dir': 'foobar'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_hooks_raises_errors_post_0'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_cli.py::test_cli_error_on_existing_output_directory
test_cli.py::test_cli_error_on_existing_output_directory
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('make_fake_project_dir', 'remove_fake_project_dir')
def test_cli_error_on_existing_output_directory(cli_runner):
"""Test cli invocation without `overwrite-if-exists` fail if dir exist."""
result = cli_runner('tests/fake-repo-pre/', '--no-input')
assert result.exit_code != 0
expected_error_msg = 'Error: "fake-project" directory already exists\n'
> assert result.output == expected_error_msg
E assert '' == 'Error: "fake-project" directory already exists\n'
E
E - Error: "fake-project" directory already exists
tests/test_cli.py:81: AssertionError
test_cli.py::test_cli
test_cli.py::test_cli
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli(cli_runner):
"""Test cli invocation work without flags if directory not exist."""
result = cli_runner('tests/fake-repo-pre/', '--no-input')
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:88: AssertionError
test_cli.py::test_cli_verbose
test_cli.py::test_cli_verbose
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_verbose(cli_runner):
"""Test cli invocation display log if called with `verbose` flag."""
result = cli_runner('tests/fake-repo-pre/', '--no-input', '-v')
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:98: AssertionError
test_cli.py::test_cli_replay
test_cli.py::test_cli_replay
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6fb27e20>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': True, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': True, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': True,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': True,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_replay(mocker, cli_runner):
"""Test cli invocation display log with `verbose` and `replay` flags."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--replay', '-v')
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=True,
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir='.',
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': True, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': True, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': True,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': True,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:113: AssertionError
test_cli.py::test_cli_replay_file
test_cli.py::test_cli_replay_file
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay='~/custom-replay-file', overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file='~/custom-replay-file')
_error_message = ._error_message at 0x7f6a6f9be560>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay='~/custom-replay-file', overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file='~/custom-replay-file')
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay='~/custom-replay-file', overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file='~/custom-replay-file')
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': '~/custom-replay-file'} == {'replay': '~/custom-replay-file', 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'skip_if_file_exists': False}
E Differing items:
E {'replay': False} != {'replay': '~/custom-replay-file'}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': '~/custom-replay-file'}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E + 'replay': False,
E - 'replay': '~/custom-replay-file',
E + 'replay_file': '~/custom-replay-file',
E ? +++++
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_replay_file(mocker, cli_runner):
"""Test cli invocation correctly pass --replay-file option."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--replay-file', '~/custom-replay-file', '-v')
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay='~/custom-replay-file',
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir='.',
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay='~/custom-replay-file', overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file='~/custom-replay-file')
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': '~/custom-replay-file'} == {'replay': '~/custom-replay-file', 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'skip_if_file_exists': False}
E Differing items:
E {'replay': False} != {'replay': '~/custom-replay-file'}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': '~/custom-replay-file'}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E + 'replay': False,
E - 'replay': '~/custom-replay-file',
E + 'replay_file': '~/custom-replay-file',
E ? +++++
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:140: AssertionError
test_cli.py::test_cli_replay_generated
test_cli.py::test_cli_replay_generated
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_tmp_dir')
def test_cli_replay_generated(mocker, cli_runner):
"""Test cli invocation correctly generates a project with replay."""
template_path = 'tests/fake-repo-replay/'
result = cli_runner(
template_path,
'--replay-file',
'tests/test-replay/valid_replay.json',
'-o',
'tests/tmp/',
'-v',
)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:170: AssertionError
test_cli.py::test_cli_exit_on_noinput_and_replay
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_exit_on_noinput_and_replay(mocker, cli_runner):
"""Test cli invocation fail if both `no-input` and `replay` flags passed."""
mock_cookiecutter = mocker.patch(
'cookiecutter.cli.cookiecutter', side_effect=cookiecutter
)
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--no-input', '--replay', '-v')
assert result.exit_code == 1
expected_error_msg = (
"You can not use both replay and no_input or extra_context at the same time."
)
> assert expected_error_msg in result.output
E AssertionError: assert 'You can not use both replay and no_input or extra_context at the same time.' in 'Error: --no-input and --replay cannot be used together.\n'
E + where 'Error: --no-input and --replay cannot be used together.\n' = .output
tests/test_cli.py:190: AssertionError
test_cli.py::test_run_cookiecutter_on_overwrite_if_exists_and_replay[-f]
test_cli.py::test_run_cookiecutter_on_overwrite_if_exists_and_replay[-f]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6fb27f40>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': True, 'overwrite_if_exists': True, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': True, 'overwrite_if_exists': True, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
overwrite_cli_flag = '-f'
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_run_cookiecutter_on_overwrite_if_exists_and_replay(
mocker, cli_runner, overwrite_cli_flag
):
"""Test cli invocation with `overwrite-if-exists` and `replay` flags."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--replay', '-v', overwrite_cli_flag)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=True,
overwrite_if_exists=True,
skip_if_file_exists=False,
output_dir='.',
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': True, 'overwrite_if_exists': True, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': True, 'overwrite_if_exists': True, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:228: AssertionError
test_cli.py::test_run_cookiecutter_on_overwrite_if_exists_and_replay[--overwrite-if-exists]
test_cli.py::test_run_cookiecutter_on_overwrite_if_exists_and_replay[--overwrite-if-exists]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f9bfa30>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': True, 'overwrite_if_exists': True, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': True, 'overwrite_if_exists': True, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
overwrite_cli_flag = '--overwrite-if-exists'
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_run_cookiecutter_on_overwrite_if_exists_and_replay(
mocker, cli_runner, overwrite_cli_flag
):
"""Test cli invocation with `overwrite-if-exists` and `replay` flags."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--replay', '-v', overwrite_cli_flag)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=True,
overwrite_if_exists=True,
skip_if_file_exists=False,
output_dir='.',
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=True, overwrite_if_exists=True, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=True, overwrite_if_exists=True, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': True, 'overwrite_if_exists': True, 'output_dir': '.', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': True, 'overwrite_if_exists': True, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': True,
E 'password': None,
E 'replay': True,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:228: AssertionError
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_does_not_exist[-f]
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_does_not_exist[-f]
cli_runner = .cli_main at 0x7f6a6fb25cf0>
overwrite_cli_flag = '-f'
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_overwrite_if_exists_when_output_dir_does_not_exist(
cli_runner, overwrite_cli_flag
):
"""Test cli invocation with `overwrite-if-exists` and `no-input` flags.
Case when output dir not exist.
"""
result = cli_runner('tests/fake-repo-pre/', '--no-input', overwrite_cli_flag)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:256: AssertionError
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_does_not_exist[--overwrite-if-exists]
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_does_not_exist[--overwrite-if-exists]
cli_runner = .cli_main at 0x7f6a6fb25cf0>
overwrite_cli_flag = '--overwrite-if-exists'
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_overwrite_if_exists_when_output_dir_does_not_exist(
cli_runner, overwrite_cli_flag
):
"""Test cli invocation with `overwrite-if-exists` and `no-input` flags.
Case when output dir not exist.
"""
result = cli_runner('tests/fake-repo-pre/', '--no-input', overwrite_cli_flag)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:256: AssertionError
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_exists[-f]
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_exists[-f]
request = >
@pytest.fixture
def make_fake_project_dir(request):
"""Create a fake project to be overwritten in the according tests."""
> os.makedirs('fake-project')
tests/test_cli.py:59:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'fake-project', mode = 511, exist_ok = False
def makedirs(name, mode=0o777, exist_ok=False):
"""makedirs(name [, mode=0o777][, exist_ok=False])
Super-mkdir; create a leaf directory and all intermediate ones. Works like
mkdir, except that any intermediate path segment (not just the rightmost)
will be created if it does not exist. If the target directory already
exists, raise an OSError if exist_ok is False. Otherwise no exception is
raised. This is recursive.
"""
head, tail = path.split(name)
if not tail:
head, tail = path.split(head)
if head and tail and not path.exists(head):
try:
makedirs(head, exist_ok=exist_ok)
except FileExistsError:
# Defeats race condition when another thread created the path
pass
cdir = curdir
if isinstance(tail, bytes):
cdir = bytes(curdir, 'ASCII')
if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists
return
try:
> mkdir(name, mode)
E FileExistsError: [Errno 17] File exists: 'fake-project'
/usr/lib/python3.10/os.py:225: FileExistsError
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_exists[--overwrite-if-exists]
test_cli.py::test_cli_overwrite_if_exists_when_output_dir_exists[--overwrite-if-exists]
request = >
@pytest.fixture
def make_fake_project_dir(request):
"""Create a fake project to be overwritten in the according tests."""
> os.makedirs('fake-project')
tests/test_cli.py:59:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'fake-project', mode = 511, exist_ok = False
def makedirs(name, mode=0o777, exist_ok=False):
"""makedirs(name [, mode=0o777][, exist_ok=False])
Super-mkdir; create a leaf directory and all intermediate ones. Works like
mkdir, except that any intermediate path segment (not just the rightmost)
will be created if it does not exist. If the target directory already
exists, raise an OSError if exist_ok is False. Otherwise no exception is
raised. This is recursive.
"""
head, tail = path.split(name)
if not tail:
head, tail = path.split(head)
if head and tail and not path.exists(head):
try:
makedirs(head, exist_ok=exist_ok)
except FileExistsError:
# Defeats race condition when another thread created the path
pass
cdir = curdir
if isinstance(tail, bytes):
cdir = bytes(curdir, 'ASCII')
if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists
return
try:
> mkdir(name, mode)
E FileExistsError: [Errno 17] File exists: 'fake-project'
/usr/lib/python3.10/os.py:225: FileExistsError
test_cli.py::test_cli_output_dir[-o]
test_cli.py::test_cli_output_dir[-o]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f9be9e0>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '-o'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output'
def test_cli_output_dir(mocker, cli_runner, output_dir_flag, output_dir):
"""Test cli invocation with `output-dir` flag changes output directory."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, output_dir_flag, output_dir)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir__o_0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:285: AssertionError
test_cli.py::test_cli_output_dir[--output-dir]
test_cli.py::test_cli_output_dir[--output-dir]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6fb26a70>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '--output-dir'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output'
def test_cli_output_dir(mocker, cli_runner, output_dir_flag, output_dir):
"""Test cli invocation with `output-dir` flag changes output directory."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, output_dir_flag, output_dir)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_output_dir___output_d0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:285: AssertionError
test_cli.py::test_cli_help[help]
test_cli.py::test_cli_help[help]
cli_runner = .cli_main at 0x7f6a6fb25cf0>
help_cli_flag = 'help'
def test_cli_help(cli_runner, help_cli_flag):
"""Test cli invocation display help message with `help` flag."""
result = cli_runner(help_cli_flag)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:312: AssertionError
test_cli.py::test_user_config
test_cli.py::test_user_config
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6fa488b0>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml',
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml',
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
user_config_path = '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml'
def test_user_config(mocker, cli_runner, user_config_path):
"""Test cli invocation works with `config-file` option."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--config-file', user_config_path)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir='.',
config_file=user_config_path,
default_config=False,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml', 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml',
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_user_config0/tests/config.yaml',
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:330: AssertionError
test_cli.py::test_default_user_config_overwrite
test_cli.py::test_default_user_config_overwrite
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', 'default_config': True, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6fa48430>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', 'default_config': True, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', 'default_config': True, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', 'default_config': True, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml',
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml',
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
user_config_path = '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml'
def test_default_user_config_overwrite(mocker, cli_runner, user_config_path):
"""Test cli invocation ignores `config-file` if `default-config` passed."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(
template_path,
'--config-file',
user_config_path,
'--default-config',
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir='.',
config_file=user_config_path,
default_config=True,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file='/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', 'default_config': True, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml', 'default_config': True, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml',
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': '/tmp/pytest-of-root/pytest-0/test_default_user_config_overw0/tests/config.yaml',
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:361: AssertionError
test_cli.py::test_default_user_config
test_cli.py::test_default_user_config
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': True, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6fb27e20>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': True, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': True, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': True, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
def test_default_user_config(mocker, cli_runner):
"""Test cli invocation accepts `default-config` flag correctly."""
mock_cookiecutter = mocker.patch('cookiecutter.cli.cookiecutter')
template_path = 'tests/fake-repo-pre/'
result = cli_runner(template_path, '--default-config')
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
skip_if_file_exists=False,
output_dir='.',
config_file=None,
default_config=True,
extra_context=None,
password=None,
directory=None,
accept_hooks=True,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, skip_if_file_exists=False, output_dir='.', config_file=None, default_config=True, extra_context=None, password=None, directory=None, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=True, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': True, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'skip_if_file_exists': False, 'output_dir': '.', 'config_file': None, 'default_config': True, 'extra_context': None, 'password': None, 'directory': None, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': True,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '.',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:387: AssertionError
test_cli.py::test_echo_undefined_variable_error
test_cli.py::test_echo_undefined_variable_error
output_dir = '/tmp/pytest-of-root/pytest-0/test_echo_undefined_variable_e0/output'
cli_runner = .cli_main at 0x7f6a6fb25cf0>
def test_echo_undefined_variable_error(output_dir, cli_runner):
"""Cli invocation return error if variable undefined in template."""
template_path = 'tests/undefined-variable/file-name/'
result = cli_runner(
'--no-input',
'--default-config',
'--output-dir',
output_dir,
template_path,
)
assert result.exit_code == 1
error = "Unable to create file '{{cookiecutter.foobar}}'"
> assert error in result.output
E assert "Unable to create file '{{cookiecutter.foobar}}'" in ''
E + where '' = .output
tests/test_cli.py:420: AssertionError
test_cli.py::test_echo_unknown_extension_error
test_cli.py::test_echo_unknown_extension_error
output_dir = '/tmp/pytest-of-root/pytest-0/test_echo_unknown_extension_er0/output'
cli_runner = .cli_main at 0x7f6a6fb25cf0>
def test_echo_unknown_extension_error(output_dir, cli_runner):
"""Cli return error if extension incorrectly defined in template."""
template_path = 'tests/test-extensions/unknown/'
result = cli_runner(
'--no-input',
'--default-config',
'--output-dir',
output_dir,
template_path,
)
assert result.exit_code == 1
> assert 'Unable to load extension: ' in result.output
E assert 'Unable to load extension: ' in ''
E + where '' = .output
tests/test_cli.py:459: AssertionError
test_cli.py::test_local_extension
test_cli.py::test_local_extension
tmpdir = local('/tmp/pytest-of-root/pytest-0/test_local_extension0')
cli_runner = .cli_main at 0x7f6a6fb25cf0>
def test_local_extension(tmpdir, cli_runner):
"""Test to verify correct work of extension, included in template."""
output_dir = str(tmpdir.mkdir('output'))
template_path = 'tests/test-extensions/local_extension/'
result = cli_runner(
'--no-input',
'--default-config',
'--output-dir',
output_dir,
template_path,
)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:474: AssertionError
test_cli.py::test_cli_extra_context
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_extra_context(cli_runner):
"""Cli invocation replace content if called with replacement pairs."""
result = cli_runner(
'tests/fake-repo-pre/',
'--no-input',
'-v',
'project_name=Awesomez',
)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:499: AssertionError
test_cli.py::test_debug_file_non_verbose
test_cli.py::test_debug_file_non_verbose
cli_runner = .cli_main at 0x7f6a6fb25cf0>
debug_file = PosixPath('/tmp/pytest-of-root/pytest-0/test_debug_file_non_verbose0/fake-repo.log')
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_debug_file_non_verbose(cli_runner, debug_file):
"""Test cli invocation writes log to `debug-file` if flag enabled.
Case for normal log output.
"""
assert not debug_file.exists()
result = cli_runner(
'--no-input',
'--debug-file',
str(debug_file),
'tests/fake-repo-pre/',
)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:539: AssertionError
test_cli.py::test_debug_file_verbose
test_cli.py::test_debug_file_verbose
cli_runner = .cli_main at 0x7f6a6fb25cf0>
debug_file = PosixPath('/tmp/pytest-of-root/pytest-0/test_debug_file_verbose0/fake-repo.log')
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_debug_file_verbose(cli_runner, debug_file):
"""Test cli invocation writes log to `debug-file` if flag enabled.
Case for verbose log output.
"""
assert not debug_file.exists()
result = cli_runner(
'--verbose',
'--no-input',
'--debug-file',
str(debug_file),
'tests/fake-repo-pre/',
)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:566: AssertionError
test_cli.py::test_debug_list_installed_templates
test_cli.py::test_debug_list_installed_templates
request = >
@pytest.fixture
def make_fake_project_dir(request):
"""Create a fake project to be overwritten in the according tests."""
> os.makedirs('fake-project')
tests/test_cli.py:59:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'fake-project', mode = 511, exist_ok = False
def makedirs(name, mode=0o777, exist_ok=False):
"""makedirs(name [, mode=0o777][, exist_ok=False])
Super-mkdir; create a leaf directory and all intermediate ones. Works like
mkdir, except that any intermediate path segment (not just the rightmost)
will be created if it does not exist. If the target directory already
exists, raise an OSError if exist_ok is False. Otherwise no exception is
raised. This is recursive.
"""
head, tail = path.split(name)
if not tail:
head, tail = path.split(head)
if head and tail and not path.exists(head):
try:
makedirs(head, exist_ok=exist_ok)
except FileExistsError:
# Defeats race condition when another thread created the path
pass
cdir = curdir
if isinstance(tail, bytes):
cdir = bytes(curdir, 'ASCII')
if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists
return
try:
> mkdir(name, mode)
E FileExistsError: [Errno 17] File exists: 'fake-project'
/usr/lib/python3.10/os.py:225: FileExistsError
test_cli.py::test_debug_list_installed_templates_failure
test_cli.py::test_debug_list_installed_templates_failure
cli_runner = .cli_main at 0x7f6a6fb25cf0>
debug_file = PosixPath('/tmp/pytest-of-root/pytest-0/test_debug_list_installed_temp1/fake-repo.log')
user_config_path = '/tmp/pytest-of-root/pytest-0/test_debug_list_installed_temp1/tests/config.yaml'
def test_debug_list_installed_templates_failure(
cli_runner, debug_file, user_config_path
):
"""Verify --list-installed command error on invocation."""
os.makedirs(os.path.dirname(user_config_path))
Path(user_config_path).write_text('cookiecutters_dir: "/notarealplace/"')
result = cli_runner(
'--list-installed', '--config-file', user_config_path, str(debug_file)
)
> assert "Error: Cannot list installed templates." in result.output
E assert 'Error: Cannot list installed templates.' in ''
E + where '' = .output
tests/test_cli.py:609: AssertionError
test_cli.py::test_directory_repo
test_cli.py::test_directory_repo
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_directory_repo(cli_runner):
"""Test cli invocation works with `directory` option."""
result = cli_runner(
'tests/fake-repo-dir/',
'--no-input',
'-v',
'--directory=my-dir',
)
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:622: AssertionError
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=yes-None-True]
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=yes-None-True]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f389120>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '-o'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output'
accept_hooks_arg = '--accept-hooks=yes', user_input = None, expected = True
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=no-None-False]
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=no-None-False]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f844b80>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '-o'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output'
accept_hooks_arg = '--accept-hooks=no', user_input = None, expected = False
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=ask-yes-True]
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=ask-yes-True]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f844dc0>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Differing items:
E {'accept_hooks': False} != {'accept_hooks': True}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E - 'accept_hooks': True,
E ? ^^^
E + 'accept_hooks': False,
E ? ^^^^
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '-o'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output'
accept_hooks_arg = '--accept-hooks=ask', user_input = 'yes', expected = True
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Differing items:
E {'accept_hooks': False} != {'accept_hooks': True}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E - 'accept_hooks': True,
E ? ^^^
E + 'accept_hooks': False,
E ? ^^^^
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=ask-no-False]
test_cli.py::test_cli_accept_hooks[-o---accept-hooks=ask-no-False]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f845240>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '-o'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output'
accept_hooks_arg = '--accept-hooks=ask', user_input = 'no', expected = False
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks__o___acc3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=yes-None-True]
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=yes-None-True]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f845120>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '--output-dir'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output'
accept_hooks_arg = '--accept-hooks=yes', user_input = None, expected = True
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': True,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': True,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output0/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=no-None-False]
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=no-None-False]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f845750>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '--output-dir'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output'
accept_hooks_arg = '--accept-hooks=no', user_input = None, expected = False
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output1/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=ask-yes-True]
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=ask-yes-True]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f846d40>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': True, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Differing items:
E {'accept_hooks': False} != {'accept_hooks': True}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E - 'accept_hooks': True,
E ? ^^^
E + 'accept_hooks': False,
E ? ^^^^
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '--output-dir'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output'
accept_hooks_arg = '--accept-hooks=ask', user_input = 'yes', expected = True
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': True, 'keep_project_on_failure': False}
E
E Common items:
E {'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Differing items:
E {'accept_hooks': False} != {'accept_hooks': True}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E - 'accept_hooks': True,
E ? ^^^
E + 'accept_hooks': False,
E ? ^^^^
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output2/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=ask-no-False]
test_cli.py::test_cli_accept_hooks[--output-dir---accept-hooks=ask-no-False]
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
expected = call('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
actual = call('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
_error_message = ._error_message at 0x7f6a6f845e10>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('tests/fake-repo-pre/', None, False)
kwargs = {'accept_hooks': False, 'config_file': None, 'default_config': False, 'directory': None, ...}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
cli_runner = .cli_main at 0x7f6a6fb25cf0>
output_dir_flag = '--output-dir'
output_dir = '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output'
accept_hooks_arg = '--accept-hooks=ask', user_input = 'no', expected = False
@pytest.mark.parametrize(
"accept_hooks_arg,user_input,expected", cli_accept_hook_arg_testdata
)
def test_cli_accept_hooks(
mocker,
cli_runner,
output_dir_flag,
output_dir,
accept_hooks_arg,
user_input,
expected,
):
"""Test cli invocation works with `accept-hooks` option."""
mock_cookiecutter = mocker.patch("cookiecutter.cli.cookiecutter")
template_path = "tests/fake-repo-pre/"
result = cli_runner(
template_path, output_dir_flag, output_dir, accept_hooks_arg, input=user_input
)
assert result.exit_code == 0
> mock_cookiecutter.assert_called_once_with(
template_path,
None,
False,
replay=False,
overwrite_if_exists=False,
output_dir=output_dir,
config_file=None,
default_config=False,
extra_context=None,
password=None,
directory=None,
skip_if_file_exists=False,
accept_hooks=expected,
keep_project_on_failure=False,
)
E AssertionError: expected call not found.
E Expected: cookiecutter('tests/fake-repo-pre/', None, False, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, extra_context=None, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False)
E Actual: cookiecutter('tests/fake-repo-pre/', checkout=None, no_input=False, extra_context=None, replay=False, overwrite_if_exists=False, output_dir='/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=False, keep_project_on_failure=False, replay_file=None)
E
E pytest introspection follows:
E
E Args:
E assert ('tests/fake-repo-pre/',) == ('tests/fake-repo-pre/', None, False)
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'tests/fake-repo-pre/',
E - None,
E - False,
E )
E Kwargs:
E assert {'checkout': None, 'no_input': False, 'extra_context': None, 'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', 'config_file': None, 'default_config': False, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False, 'replay_file': None} == {'replay': False, 'overwrite_if_exists': False, 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output', 'config_file': None, 'default_config': False, 'extra_context': None, 'password': None, 'directory': None, 'skip_if_file_exists': False, 'accept_hooks': False, 'keep_project_on_failure': False}
E
E Common items:
E {'accept_hooks': False,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E 'skip_if_file_exists': False}
E Left contains 3 more items:
E {'checkout': None, 'no_input': False, 'replay_file': None}
E
E Full diff:
E {
E 'accept_hooks': False,
E + 'checkout': None,
E 'config_file': None,
E 'default_config': False,
E 'directory': None,
E 'extra_context': None,
E 'keep_project_on_failure': False,
E + 'no_input': False,
E 'output_dir': '/tmp/pytest-of-root/pytest-0/test_cli_accept_hooks___output3/output',
E 'overwrite_if_exists': False,
E 'password': None,
E 'replay': False,
E + 'replay_file': None,
E 'skip_if_file_exists': False,
E }
tests/test_cli.py:657: AssertionError
test_cli.py::test_cli_with_json_decoding_error
test_cli.py::test_cli_with_json_decoding_error
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_with_json_decoding_error(cli_runner):
"""Test cli invocation with a malformed JSON file."""
template_path = 'tests/fake-repo-bad-json/'
result = cli_runner(template_path, '--no-input')
assert result.exit_code != 0
# Validate the error message.
# original message from json module should be included
pattern = 'Expecting \'{0,1}:\'{0,1} delimiter: line 1 column (19|20) \\(char 19\\)'
> assert re.search(pattern, result.output)
E assert None
E + where None = ("Expecting '{0,1}:'{0,1} delimiter: line 1 column (19|20) \\(char 19\\)", '')
E + where = re.search
E + and '' = .output
tests/test_cli.py:685: AssertionError
test_cli.py::test_cli_with_pre_prompt_hook
test_cli.py::test_cli_with_pre_prompt_hook
cli_runner = .cli_main at 0x7f6a6fb25cf0>
@pytest.mark.usefixtures('remove_fake_project_dir')
def test_cli_with_pre_prompt_hook(cli_runner):
"""Test cli invocation in a template with pre_prompt hook."""
template_path = 'tests/test-pyhooks/'
result = cli_runner(template_path, '--no-input')
> assert result.exit_code == 0
E assert 1 == 0
E + where 1 = .exit_code
tests/test_cli.py:699: AssertionError
test_cookiecutter_invocation.py::test_should_invoke_main
test_cookiecutter_invocation.py::test_should_invoke_main
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f9af1c0>
project_dir = 'fake-project-templated'
@pytest.mark.usefixtures('clean_system')
def test_should_invoke_main(monkeypatch, project_dir):
"""Should create a project and exit with 0 code on cli invocation."""
monkeypatch.setenv('PYTHONPATH', '.')
> exit_code = subprocess.check_call(
[sys.executable, '-m', 'cookiecutter.cli', 'tests/fake-repo-tmpl', '--no-input']
)
tests/test_cookiecutter_invocation.py:31:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
popenargs = (['/testbed/.venv/bin/python3', '-m', 'cookiecutter.cli', 'tests/fake-repo-tmpl', '--no-input'],)
kwargs = {}, retcode = 1
cmd = ['/testbed/.venv/bin/python3', '-m', 'cookiecutter.cli', 'tests/fake-repo-tmpl', '--no-input']
def check_call(*popenargs, **kwargs):
"""Run command with arguments. Wait for command to complete. If
the exit code was zero then return, otherwise raise
CalledProcessError. The CalledProcessError object will have the
return code in the returncode attribute.
The arguments are the same as for the call function. Example:
check_call(["ls", "-l"])
"""
retcode = call(*popenargs, **kwargs)
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
> raise CalledProcessError(retcode, cmd)
E subprocess.CalledProcessError: Command '['/testbed/.venv/bin/python3', '-m', 'cookiecutter.cli', 'tests/fake-repo-tmpl', '--no-input']' returned non-zero exit status 1.
/usr/lib/python3.10/subprocess.py:369: CalledProcessError
]
]
path = 'tests/fake-repo-pre/'
@pytest.mark.parametrize('path', ['tests/fake-repo-pre/', 'tests/fake-repo-pre'])
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_no_input_return_project_dir(path):
"""Verify `cookiecutter` create project dir on input with or without slash."""
> project_dir = main.cookiecutter(path, no_input=True)
tests/test_cookiecutter_local_no_input.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-pre/', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
fake-repo-pre]
fake-repo-pre]
path = 'tests/fake-repo-pre'
@pytest.mark.parametrize('path', ['tests/fake-repo-pre/', 'tests/fake-repo-pre'])
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_no_input_return_project_dir(path):
"""Verify `cookiecutter` create project dir on input with or without slash."""
> project_dir = main.cookiecutter(path, no_input=True)
tests/test_cookiecutter_local_no_input.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-pre', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_no_input.py::test_cookiecutter_no_input_extra_context
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_no_input_extra_context():
"""Verify `cookiecutter` accept `extra_context` argument."""
> main.cookiecutter(
'tests/fake-repo-pre',
no_input=True,
extra_context={'repo_name': 'fake-project-extra'},
)
tests/test_cookiecutter_local_no_input.py:50:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-pre', checkout = None, no_input = True
extra_context = {'repo_name': 'fake-project-extra'}, replay = None
overwrite_if_exists = False, output_dir = '.', config_file = None
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_no_input.py::test_cookiecutter_templated_context
test_cookiecutter_local_no_input.py::test_cookiecutter_templated_context
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_templated_context():
"""Verify Jinja2 templating correctly works in `cookiecutter.json` file."""
> main.cookiecutter('tests/fake-repo-tmpl', no_input=True)
tests/test_cookiecutter_local_no_input.py:61:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-tmpl', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_no_input.py::test_cookiecutter_no_input_return_rendered_file
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_no_input_return_rendered_file():
"""Verify Jinja2 templating correctly works in `cookiecutter.json` file."""
> project_dir = main.cookiecutter('tests/fake-repo-pre', no_input=True)
tests/test_cookiecutter_local_no_input.py:68:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-pre', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_no_input.py::test_cookiecutter_dict_values_in_context
test_cookiecutter_local_no_input.py::test_cookiecutter_dict_values_in_context
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_dict_values_in_context():
"""Verify configured dictionary from `cookiecutter.json` correctly unpacked."""
> project_dir = main.cookiecutter('tests/fake-repo-dict', no_input=True)
tests/test_cookiecutter_local_no_input.py:77:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-dict', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_no_input.py::test_cookiecutter_template_cleanup
mocker =
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_template_cleanup(mocker):
"""Verify temporary folder for zip unpacking dropped."""
mocker.patch('tempfile.mkdtemp', return_value='fake-tmp', autospec=True)
mocker.patch(
'cookiecutter.prompt.prompt_and_delete', return_value=True, autospec=True
)
> main.cookiecutter('tests/files/fake-repo-tmpl.zip', no_input=True)
tests/test_cookiecutter_local_no_input.py:133:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/files/fake-repo-tmpl.zip', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_with_input.py::test_cookiecutter_local_with_input
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fa4f970>
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_local_with_input(monkeypatch):
"""Verify simple cookiecutter run results, without extra_context provided."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default, prompts, prefix: default,
)
> main.cookiecutter('tests/fake-repo-pre/', no_input=False)
tests/test_cookiecutter_local_with_input.py:27:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-pre/', checkout = None, no_input = False
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_local_with_input.py::test_cookiecutter_input_extra_context
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a700eed70>
@pytest.mark.usefixtures('clean_system', 'remove_additional_dirs')
def test_cookiecutter_input_extra_context(monkeypatch):
"""Verify simple cookiecutter run results, with extra_context provided."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default, prompts, prefix: default,
)
> main.cookiecutter(
'tests/fake-repo-pre',
no_input=False,
extra_context={'repo_name': 'fake-project-input-extra'},
)
tests/test_cookiecutter_local_with_input.py:42:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/fake-repo-pre', checkout = None, no_input = False
extra_context = {'repo_name': 'fake-project-input-extra'}, replay = None
overwrite_if_exists = False, output_dir = '.', config_file = None
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_nested_templates.py::test_cookiecutter_nested_templates[fake-nested-templates-fake-project]
test_cookiecutter_nested_templates.py::test_cookiecutter_nested_templates[fake-nested-templates-fake-project]
mocker =
template_dir = 'fake-nested-templates', output_dir = 'fake-project'
@pytest.mark.parametrize(
"template_dir,output_dir",
[
["fake-nested-templates", "fake-project"],
["fake-nested-templates-old-style", "fake-package"],
],
)
def test_cookiecutter_nested_templates(mocker, template_dir: str, output_dir: str):
"""Verify cookiecutter nested configuration files mechanism."""
mock_generate_files = mocker.patch("cookiecutter.main.generate_files")
main_dir = (Path("tests") / template_dir).resolve()
> main.cookiecutter(f"{main_dir}", no_input=True)
tests/test_cookiecutter_nested_templates.py:21:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '/testbed/tests/fake-nested-templates', checkout = None
no_input = True, extra_context = None, replay = None
overwrite_if_exists = False, output_dir = '.', config_file = None
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_cookiecutter_nested_templates.py::test_cookiecutter_nested_templates[fake-nested-templates-old-style-fake-package]
test_cookiecutter_nested_templates.py::test_cookiecutter_nested_templates[fake-nested-templates-old-style-fake-package]
mocker =
template_dir = 'fake-nested-templates-old-style', output_dir = 'fake-package'
@pytest.mark.parametrize(
"template_dir,output_dir",
[
["fake-nested-templates", "fake-project"],
["fake-nested-templates-old-style", "fake-package"],
],
)
def test_cookiecutter_nested_templates(mocker, template_dir: str, output_dir: str):
"""Verify cookiecutter nested configuration files mechanism."""
mock_generate_files = mocker.patch("cookiecutter.main.generate_files")
main_dir = (Path("tests") / template_dir).resolve()
> main.cookiecutter(f"{main_dir}", no_input=True)
tests/test_cookiecutter_nested_templates.py:21:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '/testbed/tests/fake-nested-templates-old-style', checkout = None
no_input = True, extra_context = None, replay = None
overwrite_if_exists = False, output_dir = '.', config_file = None
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_custom_extensions_in_hooks.py::test_hook_with_extension[pre_gen_hook]
test_custom_extensions_in_hooks.py::test_hook_with_extension[pre_gen_hook]
template = 'tests/test-extensions/custom-extension-pre'
output_dir = '/tmp/pytest-of-root/pytest-0/test_hook_with_extension_pre_g0/output'
def test_hook_with_extension(template, output_dir):
"""Verify custom Jinja2 extension correctly work in hooks and file rendering.
Each file in hooks has simple tests inside and will raise error if not
correctly rendered.
"""
> project_dir = main.cookiecutter(
template,
no_input=True,
output_dir=output_dir,
extra_context={'project_slug': 'foobar', 'name': 'Cookiemonster'},
)
tests/test_custom_extensions_in_hooks.py:36:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-extensions/custom-extension-pre', checkout = None
no_input = True
extra_context = {'name': 'Cookiemonster', 'project_slug': 'foobar'}
replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_hook_with_extension_pre_g0/output'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_custom_extensions_in_hooks.py::test_hook_with_extension[post_gen_hook]
test_custom_extensions_in_hooks.py::test_hook_with_extension[post_gen_hook]
template = 'tests/test-extensions/custom-extension-post'
output_dir = '/tmp/pytest-of-root/pytest-0/test_hook_with_extension_post_0/output'
def test_hook_with_extension(template, output_dir):
"""Verify custom Jinja2 extension correctly work in hooks and file rendering.
Each file in hooks has simple tests inside and will raise error if not
correctly rendered.
"""
> project_dir = main.cookiecutter(
template,
no_input=True,
output_dir=output_dir,
extra_context={'project_slug': 'foobar', 'name': 'Cookiemonster'},
)
tests/test_custom_extensions_in_hooks.py:36:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-extensions/custom-extension-post', checkout = None
no_input = True
extra_context = {'name': 'Cookiemonster', 'project_slug': 'foobar'}
replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_hook_with_extension_post_0/output'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_default_extensions.py::test_jinja2_time_extension
test_default_extensions.py::test_jinja2_time_extension
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_jinja2_time_extension0')
def test_jinja2_time_extension(tmp_path):
"""Verify Jinja2 time extension work correctly."""
> project_dir = cookiecutter(
'tests/test-extensions/default/', no_input=True, output_dir=str(tmp_path)
)
tests/test_default_extensions.py:24:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-extensions/default/', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_jinja2_time_extension0'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_default_extensions.py::test_jinja2_slugify_extension
test_default_extensions.py::test_jinja2_slugify_extension
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_jinja2_slugify_extension0')
def test_jinja2_slugify_extension(tmp_path):
"""Verify Jinja2 slugify extension work correctly."""
> project_dir = cookiecutter(
'tests/test-extensions/default/', no_input=True, output_dir=str(tmp_path)
)
tests/test_default_extensions.py:47:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-extensions/default/', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_jinja2_slugify_extension0'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_default_extensions.py::test_jinja2_uuid_extension
test_default_extensions.py::test_jinja2_uuid_extension
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_jinja2_uuid_extension0')
def test_jinja2_uuid_extension(tmp_path):
"""Verify Jinja2 uuid extension work correctly."""
> project_dir = cookiecutter(
'tests/test-extensions/default/', no_input=True, output_dir=str(tmp_path)
)
tests/test_default_extensions.py:56:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-extensions/default/', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_jinja2_uuid_extension0'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_find.py::test_find_template[template with default jinja strings]
test_find.py::test_find_template[template with default jinja strings]
repo_name = 'fake-repo-pre', env = None
error_expectation =
expected = '{{cookiecutter.repo_name}}'
@pytest.mark.parametrize(
"repo_name,context,error_expectation,expected",
[
("fake-repo-pre", {}, does_not_raise(), '{{cookiecutter.repo_name}}'),
(
"fake-repo-pre2",
{
'cookiecutter': {
'_jinja2_env_vars': {
'variable_start_string': '{%{',
'variable_end_string': '}%}',
}
}
},
does_not_raise(),
'{%{cookiecutter.repo_name}%}',
),
(
"fake-repo-pre",
{
'cookiecutter': {
'_jinja2_env_vars': {
'variable_start_string': '{%{',
'variable_end_string': '}%}',
}
}
},
pytest.raises(NonTemplatedInputDirException),
None,
),
("fake-repo-bad", {}, pytest.raises(NonTemplatedInputDirException), None),
],
ids=[
'template with default jinja strings',
'template with custom jinja strings',
'template with custom jinja strings but folder with default jinja strings',
'template missing folder',
],
)
def test_find_template(repo_name, env, error_expectation, expected):
"""Verify correctness of `find.find_template` path detection."""
repo_dir = Path('tests', repo_name)
with error_expectation:
template = find.find_template(repo_dir, env)
test_dir = Path(repo_dir, expected)
> assert template == test_dir
E AssertionError: assert PosixPath('tests/fake-repo-pre') == PosixPath('tests/fake-repo-pre/{{cookiecutter.repo_name}}')
tests/test_find.py:72: AssertionError
test_find.py::test_find_template[template with custom jinja strings]
test_find.py::test_find_template[template with custom jinja strings]
repo_name = 'fake-repo-pre2', env = None
error_expectation =
expected = '{%{cookiecutter.repo_name}%}'
@pytest.mark.parametrize(
"repo_name,context,error_expectation,expected",
[
("fake-repo-pre", {}, does_not_raise(), '{{cookiecutter.repo_name}}'),
(
"fake-repo-pre2",
{
'cookiecutter': {
'_jinja2_env_vars': {
'variable_start_string': '{%{',
'variable_end_string': '}%}',
}
}
},
does_not_raise(),
'{%{cookiecutter.repo_name}%}',
),
(
"fake-repo-pre",
{
'cookiecutter': {
'_jinja2_env_vars': {
'variable_start_string': '{%{',
'variable_end_string': '}%}',
}
}
},
pytest.raises(NonTemplatedInputDirException),
None,
),
("fake-repo-bad", {}, pytest.raises(NonTemplatedInputDirException), None),
],
ids=[
'template with default jinja strings',
'template with custom jinja strings',
'template with custom jinja strings but folder with default jinja strings',
'template missing folder',
],
)
def test_find_template(repo_name, env, error_expectation, expected):
"""Verify correctness of `find.find_template` path detection."""
repo_dir = Path('tests', repo_name)
with error_expectation:
template = find.find_template(repo_dir, env)
test_dir = Path(repo_dir, expected)
> assert template == test_dir
E AssertionError: assert PosixPath('tests/fake-repo-pre2') == PosixPath('tests/fake-repo-pre2/{%{cookiecutter.repo_name}%}')
tests/test_find.py:72: AssertionError
test_find.py::test_find_template[template with custom jinja strings but folder with default jinja strings]
test_find.py::test_find_template[template with custom jinja strings but folder with default jinja strings]
repo_name = 'fake-repo-pre', env = None
error_expectation = <_pytest.python_api.RaisesContext object at 0x7f6a71894100>
expected = None
@pytest.mark.parametrize(
"repo_name,context,error_expectation,expected",
[
("fake-repo-pre", {}, does_not_raise(), '{{cookiecutter.repo_name}}'),
(
"fake-repo-pre2",
{
'cookiecutter': {
'_jinja2_env_vars': {
'variable_start_string': '{%{',
'variable_end_string': '}%}',
}
}
},
does_not_raise(),
'{%{cookiecutter.repo_name}%}',
),
(
"fake-repo-pre",
{
'cookiecutter': {
'_jinja2_env_vars': {
'variable_start_string': '{%{',
'variable_end_string': '}%}',
}
}
},
pytest.raises(NonTemplatedInputDirException),
None,
),
("fake-repo-bad", {}, pytest.raises(NonTemplatedInputDirException), None),
],
ids=[
'template with default jinja strings',
'template with custom jinja strings',
'template with custom jinja strings but folder with default jinja strings',
'template missing folder',
],
)
def test_find_template(repo_name, env, error_expectation, expected):
"""Verify correctness of `find.find_template` path detection."""
repo_dir = Path('tests', repo_name)
with error_expectation:
template = find.find_template(repo_dir, env)
> test_dir = Path(repo_dir, expected)
tests/test_find.py:71:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/pathlib.py:960: in __new__
self = cls._from_parts(args)
/usr/lib/python3.10/pathlib.py:594: in _from_parts
drv, root, parts = self._parse_args(args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls =
args = (PosixPath('tests/fake-repo-pre'), None)
@classmethod
def _parse_args(cls, args):
# This is useful when you don't want to create an instance, just
# canonicalize some constructor arguments.
parts = []
for a in args:
if isinstance(a, PurePath):
parts += a._parts
else:
> a = os.fspath(a)
E TypeError: expected str, bytes or os.PathLike object, not NoneType
/usr/lib/python3.10/pathlib.py:578: TypeError
test_generate_context.py::test_generate_context[input_params0-expected_context0]
test_generate_context.py::test_generate_context[input_params0-expected_context0]
input_params = {'context_file': 'tests/test-generate-context/test.json'}
expected_context = {'test': {'1': 2, 'some_key': 'some_val'}}
@pytest.mark.usefixtures('clean_system')
@pytest.mark.parametrize('input_params, expected_context', context_data())
def test_generate_context(input_params, expected_context):
"""Verify input contexts combinations result in expected content on output."""
> assert generate.generate_context(**input_params) == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('1', 2), ('some_key', 'some_val')])} == {'test': {'1': 2, 'some_key': 'some_val'}}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('1', 2), ('some_key', 'some_val')])}
E Right contains 1 more item:
E {'test': {'1': 2, 'some_key': 'some_val'}}
E
E Full diff:
E {
E - 'test': {
E + 'cookiecutter': OrderedDict({
E '1': 2,
E 'some_key': 'some_val',
E - },
E + }),
E ? +
E }
tests/test_generate_context.py:58: AssertionError
test_generate_context.py::test_generate_context[input_params1-expected_context1]
test_generate_context.py::test_generate_context[input_params1-expected_context1]
input_params = {'context_file': 'tests/test-generate-context/test.json', 'default_context': {'1': 3}}
expected_context = {'test': {'1': 3, 'some_key': 'some_val'}}
@pytest.mark.usefixtures('clean_system')
@pytest.mark.parametrize('input_params, expected_context', context_data())
def test_generate_context(input_params, expected_context):
"""Verify input contexts combinations result in expected content on output."""
> assert generate.generate_context(**input_params) == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('1', 3), ('some_key', 'some_val')])} == {'test': {'1': 3, 'some_key': 'some_val'}}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('1', 3), ('some_key', 'some_val')])}
E Right contains 1 more item:
E {'test': {'1': 3, 'some_key': 'some_val'}}
E
E Full diff:
E {
E - 'test': {
E + 'cookiecutter': OrderedDict({
E '1': 3,
E 'some_key': 'some_val',
E - },
E + }),
E ? +
E }
tests/test_generate_context.py:58: AssertionError
test_generate_context.py::test_generate_context[input_params2-expected_context2]
test_generate_context.py::test_generate_context[input_params2-expected_context2]
input_params = {'context_file': 'tests/test-generate-context/test.json', 'extra_context': {'1': 4}}
expected_context = {'test': {'1': 4, 'some_key': 'some_val'}}
@pytest.mark.usefixtures('clean_system')
@pytest.mark.parametrize('input_params, expected_context', context_data())
def test_generate_context(input_params, expected_context):
"""Verify input contexts combinations result in expected content on output."""
> assert generate.generate_context(**input_params) == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('1', 4), ('some_key', 'some_val')])} == {'test': {'1': 4, 'some_key': 'some_val'}}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('1', 4), ('some_key', 'some_val')])}
E Right contains 1 more item:
E {'test': {'1': 4, 'some_key': 'some_val'}}
E
E Full diff:
E {
E - 'test': {
E + 'cookiecutter': OrderedDict({
E '1': 4,
E 'some_key': 'some_val',
E - },
E + }),
E ? +
E }
tests/test_generate_context.py:58: AssertionError
test_generate_context.py::test_generate_context[input_params3-expected_context3]
test_generate_context.py::test_generate_context[input_params3-expected_context3]
input_params = {'context_file': 'tests/test-generate-context/test.json', 'default_context': {'1': 3}, 'extra_context': {'1': 5}}
expected_context = {'test': {'1': 5, 'some_key': 'some_val'}}
@pytest.mark.usefixtures('clean_system')
@pytest.mark.parametrize('input_params, expected_context', context_data())
def test_generate_context(input_params, expected_context):
"""Verify input contexts combinations result in expected content on output."""
> assert generate.generate_context(**input_params) == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('1', 5), ('some_key', 'some_val')])} == {'test': {'1': 5, 'some_key': 'some_val'}}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('1', 5), ('some_key', 'some_val')])}
E Right contains 1 more item:
E {'test': {'1': 5, 'some_key': 'some_val'}}
E
E Full diff:
E {
E - 'test': {
E + 'cookiecutter': OrderedDict({
E '1': 5,
E 'some_key': 'some_val',
E - },
E + }),
E ? +
E }
tests/test_generate_context.py:58: AssertionError
test_generate_context.py::test_default_context_replacement_in_generate_context
test_generate_context.py::test_default_context_replacement_in_generate_context
def test_default_context_replacement_in_generate_context():
"""Verify default content settings are correctly replaced by template settings.
Make sure that the default for list variables of `orientation` is based on
the user config (`choices_template.json`) and not changed to a single value
from `default_context`.
"""
expected_context = {
'choices_template': OrderedDict(
[
('full_name', 'Raphael Pierzina'),
('github_username', 'hackebrot'),
('project_name', 'Kivy Project'),
('repo_name', '{{cookiecutter.project_name|lower}}'),
('orientation', ['landscape', 'all', 'portrait']),
]
)
}
generated_context = generate.generate_context(
context_file='tests/test-generate-context/choices_template.json',
default_context={
'not_in_template': 'foobar',
'project_name': 'Kivy Project',
'orientation': 'landscape',
},
extra_context={
'also_not_in_template': 'foobar2',
'github_username': 'hackebrot',
},
)
> assert generated_context == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', 'landscape'), ('not_in_template', 'foobar'), ('also_not_in_template', 'foobar2')])} == {'choices_template': OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['landscape', 'all', 'portrait'])])}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('full_name', 'Raphael Pierzina'),
E ('github_username', 'hackebrot'),
E ('project_name', 'Kivy Project'),
E ('repo_name',
E '{{cookiecutter.project_name|lower}}'),
E ('orientation', 'landscape'),
E ('not_in_template', 'foobar'),
E ('also_not_in_template', 'foobar2')])}
E Right contains 1 more item:
E {'choices_template': OrderedDict([('full_name', 'Raphael Pierzina'),
E ('github_username', 'hackebrot'),
E ('project_name', 'Kivy Project'),
E ('repo_name',
E '{{cookiecutter.project_name|lower}}'),
E ('orientation',
E ['landscape', 'all', 'portrait'])])}
E
E Full diff:
E {
E - 'choices_template': OrderedDict({
E ? - ^^^ ^^^^^^
E + 'cookiecutter': OrderedDict({
E ? ++ + ^^ ^
E + 'also_not_in_template': 'foobar2',
E 'full_name': 'Raphael Pierzina',
E 'github_username': 'hackebrot',
E + 'not_in_template': 'foobar',
E - 'orientation': [
E ? ^
E + 'orientation': 'landscape',
E ? ^^^^^^^^^^^^
E - 'landscape',
E - 'all',
E - 'portrait',
E - ],
E 'project_name': 'Kivy Project',
E 'repo_name': '{{cookiecutter.project_name|lower}}',
E }),
E }
tests/test_generate_context.py:109: AssertionError
test_generate_context.py::test_generate_context_decodes_non_ascii_chars
test_generate_context.py::test_generate_context_decodes_non_ascii_chars
def test_generate_context_decodes_non_ascii_chars():
"""Verify `generate_context` correctly decodes non-ascii chars."""
expected_context = {
'non_ascii': OrderedDict(
[
('full_name', 'éèà'),
]
)
}
generated_context = generate.generate_context(
context_file='tests/test-generate-context/non_ascii.json'
)
> assert generated_context == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('full_name', 'éèà')])} == {'non_ascii': OrderedDict([('full_name', 'éèà')])}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('full_name', 'éèà')])}
E Right contains 1 more item:
E {'non_ascii': OrderedDict([('full_name', 'éèà')])}
E
E Full diff:
E {
E - 'non_ascii': OrderedDict({
E + 'cookiecutter': OrderedDict({
E 'full_name': 'éèà',
E }),
E }
tests/test_generate_context.py:126: AssertionError
test_generate_context.py::test_apply_overwrites_does_include_unused_variables
test_generate_context.py::test_apply_overwrites_does_include_unused_variables
template_context = OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['all', 'landscape', 'portrait']), ('deployment_regions', ['eu', 'us', 'ap']), ('deployments', {'preprod': ['eu', 'us', 'ap'], 'prod': ['eu', 'us', 'ap']}), ('not in template', 'foobar')])
def test_apply_overwrites_does_include_unused_variables(template_context):
"""Verify `apply_overwrites_to_context` skips variables that are not in context."""
generate.apply_overwrites_to_context(
context=template_context, overwrite_context={'not in template': 'foobar'}
)
> assert 'not in template' not in template_context
E AssertionError: assert 'not in template' not in OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['all', 'landscape', 'portrait']), ('deployment_regions', ['eu', 'us', 'ap']), ('deployments', {'preprod': ['eu', 'us', 'ap'], 'prod': ['eu', 'us', 'ap']}), ('not in template', 'foobar')])
tests/test_generate_context.py:157: AssertionError
test_generate_context.py::test_apply_overwrites_does_not_modify_choices_for_invalid_overwrite
test_generate_context.py::test_apply_overwrites_does_not_modify_choices_for_invalid_overwrite
def test_apply_overwrites_does_not_modify_choices_for_invalid_overwrite():
"""Verify variables overwrite for list if variable not in list ignored."""
expected_context = {
'choices_template': OrderedDict(
[
('full_name', 'Raphael Pierzina'),
('github_username', 'hackebrot'),
('project_name', 'Kivy Project'),
('repo_name', '{{cookiecutter.project_name|lower}}'),
('orientation', ['all', 'landscape', 'portrait']),
]
)
}
> with pytest.warns(UserWarning, match="Invalid default received"):
E Failed: DID NOT WARN. No warnings of type (,) were emitted.
E Emitted warnings: [].
tests/test_generate_context.py:183: Failed
test_generate_context.py::test_apply_overwrites_invalid_overwrite
test_generate_context.py::test_apply_overwrites_invalid_overwrite
template_context = OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', 'foobar'), ('deployment_regions', ['eu', 'us', 'ap']), ('deployments', {'preprod': ['eu', 'us', 'ap'], 'prod': ['eu', 'us', 'ap']})])
def test_apply_overwrites_invalid_overwrite(template_context):
"""Verify variables overwrite for list if variable not in list not ignored."""
> with pytest.raises(ValueError):
E Failed: DID NOT RAISE
tests/test_generate_context.py:202: Failed
test_generate_context.py::test_apply_overwrites_invalid_multichoice_values
test_generate_context.py::test_apply_overwrites_invalid_multichoice_values
template_context = OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['all', 'landscape', 'portrait']), ('deployment_regions', ['na']), ('deployments', {'preprod': ['eu', 'us', 'ap'], 'prod': ['eu', 'us', 'ap']})])
def test_apply_overwrites_invalid_multichoice_values(template_context):
"""Verify variable overwrite for list given invalid list entries not ignored."""
> with pytest.raises(ValueError):
E Failed: DID NOT RAISE
tests/test_generate_context.py:219: Failed
test_generate_context.py::test_apply_overwrites_error_additional_values
test_generate_context.py::test_apply_overwrites_error_additional_values
template_context = OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['all', 'landscape', 'portrait']), ('deployment_regions', ['eu', 'na']), ('deployments', {'preprod': ['eu', 'us', 'ap'], 'prod': ['eu', 'us', 'ap']})])
def test_apply_overwrites_error_additional_values(template_context):
"""Verify variable overwrite for list given additional entries not ignored."""
> with pytest.raises(ValueError):
E Failed: DID NOT RAISE
tests/test_generate_context.py:228: Failed
test_generate_context.py::test_apply_overwrites_sets_default_for_choice_variable
test_generate_context.py::test_apply_overwrites_sets_default_for_choice_variable
template_context = OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project_name', 'Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', 'landscape'), ('deployment_regions', ['eu', 'us', 'ap']), ('deployments', {'preprod': ['eu', 'us', 'ap'], 'prod': ['eu', 'us', 'ap']})])
def test_apply_overwrites_sets_default_for_choice_variable(template_context):
"""Verify overwritten list member became a default value."""
generate.apply_overwrites_to_context(
context=template_context, overwrite_context={'orientation': 'landscape'}
)
> assert template_context['orientation'] == ['landscape', 'all', 'portrait']
E AssertionError: assert 'landscape' == ['landscape', 'all', 'portrait']
tests/test_generate_context.py:251: AssertionError
test_generate_context.py::test_apply_overwrites_in_nested_dict
test_generate_context.py::test_apply_overwrites_in_nested_dict
def test_apply_overwrites_in_nested_dict():
"""Verify nested dict in default content settings are correctly replaced."""
expected_context = {
'nested_dict': OrderedDict(
[
('full_name', 'Raphael Pierzina'),
('github_username', 'hackebrot'),
(
'project',
OrderedDict(
[
('name', 'My Kivy Project'),
('description', 'My Kivy Project'),
('repo_name', '{{cookiecutter.project_name|lower}}'),
('orientation', ["all", "landscape", "portrait"]),
]
),
),
]
)
}
generated_context = generate.generate_context(
context_file='tests/test-generate-context/nested_dict.json',
default_context={
'not_in_template': 'foobar',
'project': {
'description': 'My Kivy Project',
},
},
extra_context={
'also_not_in_template': 'foobar2',
'github_username': 'hackebrot',
'project': {
'name': 'My Kivy Project',
},
},
)
> assert generated_context == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project', OrderedDict([('name', 'My Kivy Project'), ('description', 'My Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['all', 'landscape', 'portrait'])])), ('not_in_template', 'foobar'), ('also_not_in_template', 'foobar2')])} == {'nested_dict': OrderedDict([('full_name', 'Raphael Pierzina'), ('github_username', 'hackebrot'), ('project', OrderedDict([('name', 'My Kivy Project'), ('description', 'My Kivy Project'), ('repo_name', '{{cookiecutter.project_name|lower}}'), ('orientation', ['all', 'landscape', 'portrait'])]))])}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('full_name', 'Raphael Pierzina'),
E ('github_username', 'hackebrot'),
E ('project',
E OrderedDict([('name', 'My Kivy Project'),
E ('description', 'My Kivy Project'),
E ('repo_name',
E '{{cookiecutter.project_name|lower}}'),
E ('orientation',
E ['all',
E 'landscape',
E 'portrait'])])),
E ('not_in_template', 'foobar'),
E ('also_not_in_template', 'foobar2')])}
E Right contains 1 more item:
E {'nested_dict': OrderedDict([('full_name', 'Raphael Pierzina'),
E ('github_username', 'hackebrot'),
E ('project',
E OrderedDict([('name', 'My Kivy Project'),
E ('description', 'My Kivy Project'),
E ('repo_name',
E '{{cookiecutter.project_name|lower}}'),
E ('orientation',
E ['all',
E 'landscape',
E 'portrait'])]))])}
E
E Full diff:
E {
E - 'nested_dict': OrderedDict({
E + 'cookiecutter': OrderedDict({
E + 'also_not_in_template': 'foobar2',
E 'full_name': 'Raphael Pierzina',
E 'github_username': 'hackebrot',
E + 'not_in_template': 'foobar',
E 'project': OrderedDict({
E 'description': 'My Kivy Project',
E 'name': 'My Kivy Project',
E 'orientation': [
E 'all',
E 'landscape',
E 'portrait',
E ],
E 'repo_name': '{{cookiecutter.project_name|lower}}',
E }),
E }),
E }
tests/test_generate_context.py:293: AssertionError
test_generate_context.py::test_apply_overwrites_in_nested_dict_additional_values
test_generate_context.py::test_apply_overwrites_in_nested_dict_additional_values
def test_apply_overwrites_in_nested_dict_additional_values():
"""Verify nested dict in default content settings are correctly added."""
expected_context = {
'nested_dict_additional': OrderedDict(
[
('mainkey1', 'mainvalue1'),
(
'mainkey2',
OrderedDict(
[
('subkey1', 'subvalue1'),
(
'subkey2',
OrderedDict(
[
('subsubkey1', 'subsubvalue1'),
('subsubkey2', 'subsubvalue2_default'),
('subsubkey3', 'subsubvalue3_extra'),
]
),
),
('subkey4', 'subvalue4_default'),
('subkey5', 'subvalue5_extra'),
]
),
),
]
)
}
generated_context = generate.generate_context(
context_file='tests/test-generate-context/nested_dict_additional.json',
default_context={
'not_in_template': 'foobar',
'mainkey2': {
'subkey2': {
'subsubkey2': 'subsubvalue2_default',
},
'subkey4': 'subvalue4_default',
},
},
extra_context={
'also_not_in_template': 'foobar2',
'mainkey2': {
'subkey2': {
'subsubkey3': 'subsubvalue3_extra',
},
'subkey5': 'subvalue5_extra',
},
},
)
> assert generated_context == expected_context
E AssertionError: assert {'cookiecutter': OrderedDict([('mainkey1', 'mainvalue1'), ('mainkey2', OrderedDict([('subkey1', 'subvalue1'), ('subkey2', OrderedDict([('subsubkey1', 'subsubvalue1'), ('subsubkey2', 'subsubvalue2_default'), ('subsubkey3', 'subsubvalue3_extra')])), ('subkey4', 'subvalue4_default'), ('subkey5', 'subvalue5_extra')])), ('not_in_template', 'foobar'), ('also_not_in_template', 'foobar2')])} == {'nested_dict_additional': OrderedDict([('mainkey1', 'mainvalue1'), ('mainkey2', OrderedDict([('subkey1', 'subvalue1'), ('subkey2', OrderedDict([('subsubkey1', 'subsubvalue1'), ('subsubkey2', 'subsubvalue2_default'), ('subsubkey3', 'subsubvalue3_extra')])), ('subkey4', 'subvalue4_default'), ('subkey5', 'subvalue5_extra')]))])}
E
E Left contains 1 more item:
E {'cookiecutter': OrderedDict([('mainkey1', 'mainvalue1'),
E ('mainkey2',
E OrderedDict([('subkey1', 'subvalue1'),
E ('subkey2',
E OrderedDict([('subsubkey1',
E 'subsubvalue1'),
E ('subsubkey2',
E 'subsubvalue2_default'),
E ('subsubkey3',
E 'subsubvalue3_extra')])),
E ('subkey4', 'subvalue4_default'),
E ('subkey5', 'subvalue5_extra')])),
E ('not_in_template', 'foobar'),
E ('also_not_in_template', 'foobar2')])}
E Right contains 1 more item:
E {'nested_dict_additional': OrderedDict([('mainkey1', 'mainvalue1'),
E ('mainkey2',
E OrderedDict([('subkey1', 'subvalue1'),
E ('subkey2',
E OrderedDict([('subsubkey1',
E 'subsubvalue1'),
E ('subsubkey2',
E 'subsubvalue2_default'),
E ('subsubkey3',
E 'subsubvalue3_extra')])),
E ('subkey4',
E 'subvalue4_default'),
E ('subkey5',
E 'subvalue5_extra')]))])}
E
E Full diff:
E {
E - 'nested_dict_additional': OrderedDict({
E + 'cookiecutter': OrderedDict({
E + 'also_not_in_template': 'foobar2',
E 'mainkey1': 'mainvalue1',
E 'mainkey2': OrderedDict({
E 'subkey1': 'subvalue1',
E 'subkey2': OrderedDict({
E 'subsubkey1': 'subsubvalue1',
E 'subsubkey2': 'subsubvalue2_default',
E 'subsubkey3': 'subsubvalue3_extra',
E }),
E 'subkey4': 'subvalue4_default',
E 'subkey5': 'subvalue5_extra',
E }),
E + 'not_in_template': 'foobar',
E }),
E }
tests/test_generate_context.py:364: AssertionError
test_generate_copy_without_render.py::test_generate_copy_without_render_extensions
test_generate_copy_without_render.py::test_generate_copy_without_render_extensions
@pytest.mark.usefixtures('clean_system', 'remove_test_dir')
def test_generate_copy_without_render_extensions():
"""Verify correct work of `_copy_without_render` context option.
Some files/directories should be rendered during invocation,
some just copied, without any modification.
"""
> generate.generate_files(
context={
'cookiecutter': {
'repo_name': 'test_copy_without_render',
'render_test': 'I have been rendered!',
'_copy_without_render': [
'*not-rendered',
'rendered/not_rendered.yml',
'*.txt',
'{{cookiecutter.repo_name}}-rendered/README.md',
],
}
},
repo_dir='tests/test-generate-copy-without-render',
)
tests/test_generate_copy_without_render.py:26:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-copy-without-render'
context = {'cookiecutter': {'_copy_without_render': ['*not-rendered', 'rendered/not_rendered.yml', '*.txt', '{{cookiecutter.repo_name}}-rendered/README.md'], 'render_test': 'I have been rendered!', 'repo_name': 'test_copy_without_render'}}
output_dir = '.', overwrite_if_exists = False, skip_if_file_exists = False
accept_hooks = True, keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_copy_without_render_override.py::test_generate_copy_without_render_extensions
test_generate_copy_without_render_override.py::test_generate_copy_without_render_extensions
@pytest.mark.usefixtures('clean_system', 'remove_test_dir')
def test_generate_copy_without_render_extensions():
"""Verify correct work of `_copy_without_render` context option.
Some files/directories should be rendered during invocation,
some just copied, without any modification.
"""
# first run
> generate.generate_files(
context={
'cookiecutter': {
'repo_name': 'test_copy_without_render',
'render_test': 'I have been rendered!',
'_copy_without_render': [
'*not-rendered',
'rendered/not_rendered.yml',
'*.txt',
'{{cookiecutter.repo_name}}-rendered/README.md',
],
}
},
repo_dir='tests/test-generate-copy-without-render-override',
)
tests/test_generate_copy_without_render_override.py:27:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-copy-without-render-override'
context = {'cookiecutter': {'_copy_without_render': ['*not-rendered', 'rendered/not_rendered.yml', '*.txt', '{{cookiecutter.repo_name}}-rendered/README.md'], 'render_test': 'I have been rendered!', 'repo_name': 'test_copy_without_render'}}
output_dir = '.', overwrite_if_exists = False, skip_if_file_exists = False
accept_hooks = True, keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_file.py::test_generate_file_with_false_condition
test_generate_file.py::test_generate_file_with_false_condition
env =
def test_generate_file_with_false_condition(env):
"""Verify correct work of boolean condition in file name on file generation.
This test has negative answer, so file should not be rendered.
"""
infile = (
'tests/files/{% if cookiecutter.generate_file == \'y\' %}cheese.txt{% endif %}'
)
> generate.generate_file(
project_dir=".",
infile=infile,
context={'cookiecutter': {'generate_file': 'n'}},
env=env,
)
tests/test_generate_file.py:110:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
project_dir = '.'
infile = "tests/files/{% if cookiecutter.generate_file == 'y' %}cheese.txt{% endif %}"
context = {'cookiecutter': {'generate_file': 'n'}}
env =
skip_if_file_exists = False
def generate_file(project_dir, infile, context, env, skip_if_file_exists=False):
"""Render filename of infile as name of outfile, handle infile correctly.
Dealing with infile appropriately:
a. If infile is a binary file, copy it over without rendering.
b. If infile is a text file, render its contents and write the
rendered infile to outfile.
Precondition:
When calling `generate_file()`, the root template dir must be the
current working directory. Using `utils.work_in()` is the recommended
way to perform this directory change.
:param project_dir: Absolute path to the resulting generated project.
:param infile: Input file to generate the file from. Relative to the root
template dir.
:param context: Dict for populating the cookiecutter's variables.
:param env: Jinja2 template execution environment.
"""
logger.debug('Processing file %s', infile)
# Render the path to the output file (not the contents of the input file)
outfile_tmpl = env.from_string(infile)
outfile = outfile_tmpl.render(**context)
outfile_path = os.path.join(project_dir, outfile)
# Skip if file exists
if skip_if_file_exists and os.path.exists(outfile_path):
logger.debug('File %s already exists, skipping', outfile)
return []
# Create the parent directory if it doesn't exist
parent_dir = os.path.dirname(outfile_path)
if parent_dir and not os.path.exists(parent_dir):
make_sure_path_exists(parent_dir)
# Just copy over binary files without rendering
logger.debug("Check %s to see if it's a binary", infile)
if is_binary(infile) or is_copy_only_path(infile, context):
logger.debug('Copying binary %s to %s without rendering', infile, outfile)
shutil.copyfile(infile, outfile_path)
return [outfile_path]
# For text files, render the contents and write the rendered file
try:
with open(infile, encoding='utf-8') as f:
tmpl = env.from_string(f.read())
rendered_file = tmpl.render(**context)
logger.debug('Writing %s', outfile)
> with open(outfile_path, 'w', encoding='utf-8') as fh:
E IsADirectoryError: [Errno 21] Is a directory: './tests/files/'
cookiecutter/generate.py:134: IsADirectoryError
test_generate_file.py::test_generate_file_verbose_template_syntax_error
test_generate_file.py::test_generate_file_verbose_template_syntax_error
env =
expected_msg_regex = re.compile('Missing end of comment tag\n {2}File "(.[/\\\\])*tests[/\\\\]files[/\\\\]syntax_error.txt", line 1\n {4}I eat {{ syntax_error }} {# this comment is not closed}')
def test_generate_file_verbose_template_syntax_error(env, expected_msg_regex):
"""Verify correct exception raised on syntax error in file before generation."""
with pytest.raises(TemplateSyntaxError) as exception:
generate.generate_file(
project_dir=".",
infile='tests/files/syntax_error.txt',
context={'syntax_error': 'syntax_error'},
env=env,
)
> assert expected_msg_regex.match(str(exception.value))
E assert None
E + where None = ('Missing end of comment tag\n File "tests/files/syntax_error.txt", line 1')
E + where = re.compile('Missing end of comment tag\n {2}File "(.[/\\\\])*tests[/\\\\]files[/\\\\]syntax_error.txt", line 1\n {4}I eat {{ syntax_error }} {# this comment is not closed}').match
E + and 'Missing end of comment tag\n File "tests/files/syntax_error.txt", line 1' = str(TemplateSyntaxError('Missing end of comment tag'))
E + where TemplateSyntaxError('Missing end of comment tag') = .value
tests/test_generate_file.py:138: AssertionError
test_generate_file.py::test_generate_file_does_not_translate_crlf_newlines_to_lf
test_generate_file.py::test_generate_file_does_not_translate_crlf_newlines_to_lf
env =
def test_generate_file_does_not_translate_crlf_newlines_to_lf(env):
"""Verify that file generation use same line ending, as in source file."""
infile = 'tests/files/{{cookiecutter.generate_file}}_crlf_newlines.txt'
generate.generate_file(
project_dir=".",
infile=infile,
context={'cookiecutter': {'generate_file': 'cheese'}},
env=env,
)
# this generated file should have a CRLF line ending
gf = 'tests/files/cheese_crlf_newlines.txt'
with Path(gf).open(encoding='utf-8', newline='') as f:
simple_text = f.readline()
> assert simple_text == 'newline is CRLF\r\n'
E AssertionError: assert 'newline is CRLF\n' == 'newline is CRLF\r\n'
E
E - newline is CRLF
E ? -
E + newline is CRLF
tests/test_generate_file.py:173: AssertionError
test_generate_files.py::test_generate_files_nontemplated_exception
test_generate_files.py::test_generate_files_nontemplated_exception
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_nontemplat0')
def test_generate_files_nontemplated_exception(tmp_path):
"""
Verify `generate_files` raises when no directories to render exist.
Note: Check `tests/test-generate-files-nontemplated` location to understand.
"""
with pytest.raises(exceptions.NonTemplatedInputDirException):
> generate.generate_files(
context={'cookiecutter': {'food': 'pizza'}},
repo_dir='tests/test-generate-files-nontemplated',
output_dir=tmp_path,
)
tests/test_generate_files.py:22:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files-nontemplated'
context = {'cookiecutter': {'food': 'pizza'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_nontemplat0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files
test_generate_files.py::test_generate_files
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files0')
def test_generate_files(tmp_path):
"""Verify directory name correctly rendered with unicode containing context."""
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir='tests/test-generate-files',
output_dir=tmp_path,
)
tests/test_generate_files.py:31:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_linux_newline
test_generate_files.py::test_generate_files_with_linux_newline
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_linux0')
def test_generate_files_with_linux_newline(tmp_path):
"""Verify new line not removed by templating engine after folder generation."""
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir='tests/test-generate-files',
output_dir=tmp_path,
)
tests/test_generate_files.py:47:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_linux0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_jinja2_environment
test_generate_files.py::test_generate_files_with_jinja2_environment
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_jinja0')
def test_generate_files_with_jinja2_environment(tmp_path):
"""Extend StrictEnvironment with _jinja2_env_vars cookiecutter template option."""
> generate.generate_files(
context={
'cookiecutter': {
'food': 'pizzä',
'_jinja2_env_vars': {'lstrip_blocks': True, 'trim_blocks': True},
}
},
repo_dir='tests/test-generate-files',
output_dir=tmp_path,
)
tests/test_generate_files.py:65:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'_jinja2_env_vars': {'lstrip_blocks': True, 'trim_blocks': True}, 'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_jinja0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_trailing_newline_forced_to_linux_by_context
test_generate_files.py::test_generate_files_with_trailing_newline_forced_to_linux_by_context
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_trail0')
def test_generate_files_with_trailing_newline_forced_to_linux_by_context(tmp_path):
"""Verify new line not removed by templating engine after folder generation."""
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä', '_new_lines': '\r\n'}},
repo_dir='tests/test-generate-files',
output_dir=tmp_path,
)
tests/test_generate_files.py:86:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'_new_lines': '\r\n', 'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_trail0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_windows_newline
test_generate_files.py::test_generate_files_with_windows_newline
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_windo0')
def test_generate_files_with_windows_newline(tmp_path):
"""Verify windows source line end not changed during files generation."""
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir='tests/test-generate-files',
output_dir=tmp_path,
)
tests/test_generate_files.py:105:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_windo0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_windows_newline_forced_to_linux_by_context
test_generate_files.py::test_generate_files_with_windows_newline_forced_to_linux_by_context
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_windo1')
def test_generate_files_with_windows_newline_forced_to_linux_by_context(tmp_path):
"""Verify windows line end changed to linux during files generation."""
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä', '_new_lines': '\n'}},
repo_dir='tests/test-generate-files',
output_dir=tmp_path,
)
tests/test_generate_files.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'_new_lines': '\n', 'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_windo1')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_binaries
test_generate_files.py::test_generate_files_binaries
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_binaries0')
def test_generate_files_binaries(tmp_path):
"""Verify binary files created during directory generation."""
> generate.generate_files(
context={'cookiecutter': {'binary_test': 'binary_files'}},
repo_dir='tests/test-generate-binaries',
output_dir=tmp_path,
)
tests/test_generate_files.py:142:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-binaries'
context = {'cookiecutter': {'binary_test': 'binary_files'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_binaries0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_absolute_path
test_generate_files.py::test_generate_files_absolute_path
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_absolute_p0')
def test_generate_files_absolute_path(tmp_path):
"""Verify usage of absolute path does not change files generation behaviour."""
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir=Path('tests/test-generate-files').absolute(),
output_dir=tmp_path,
)
tests/test_generate_files.py:163:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = PosixPath('/testbed/tests/test-generate-files')
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_absolute_p0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_output_dir
test_generate_files.py::test_generate_files_output_dir
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_output_dir0')
def test_generate_files_output_dir(tmp_path):
"""Verify `output_dir` option for `generate_files` changing location correctly."""
output_dir = Path(tmp_path, 'custom_output_dir')
output_dir.mkdir()
> project_dir = generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir=Path('tests/test-generate-files').absolute(),
output_dir=output_dir,
)
tests/test_generate_files.py:176:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = PosixPath('/testbed/tests/test-generate-files')
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_output_dir0/custom_output_dir')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_permissions
test_generate_files.py::test_generate_files_permissions
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_permission0')
def test_generate_files_permissions(tmp_path):
"""Verify generates files respect source files permissions.
simple.txt and script.sh should retain their respective 0o644 and 0o755
permissions.
"""
> generate.generate_files(
context={'cookiecutter': {'permissions': 'permissions'}},
repo_dir='tests/test-generate-files-permissions',
output_dir=tmp_path,
)
tests/test_generate_files.py:193:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files-permissions'
context = {'cookiecutter': {'permissions': 'permissions'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_permission0')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_overwrite_if_exists_with_skip_if_file_exists
test_generate_files.py::test_generate_files_with_overwrite_if_exists_with_skip_if_file_exists
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_overw0')
def test_generate_files_with_overwrite_if_exists_with_skip_if_file_exists(tmp_path):
"""Verify `skip_if_file_exist` has priority over `overwrite_if_exists`."""
simple_file = Path(tmp_path, 'inputpizzä/simple.txt')
simple_with_new_line_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt')
Path(tmp_path, 'inputpizzä').mkdir(parents=True)
with Path(simple_file).open('w') as f:
f.write('temp')
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir='tests/test-generate-files',
overwrite_if_exists=True,
skip_if_file_exists=True,
output_dir=tmp_path,
)
tests/test_generate_files.py:240:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_overw0')
overwrite_if_exists = True, skip_if_file_exists = True, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_skip_if_file_exists
test_generate_files.py::test_generate_files_with_skip_if_file_exists
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_skip_0')
def test_generate_files_with_skip_if_file_exists(tmp_path):
"""Verify existed files not removed if error raised with `skip_if_file_exists`."""
simple_file = Path(tmp_path, 'inputpizzä/simple.txt')
simple_with_new_line_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt')
Path(tmp_path, 'inputpizzä').mkdir(parents=True)
Path(simple_file).write_text('temp')
with pytest.raises(exceptions.OutputDirExistsException):
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir='tests/test-generate-files',
skip_if_file_exists=True,
output_dir=tmp_path,
)
tests/test_generate_files.py:266:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_skip_0')
overwrite_if_exists = False, skip_if_file_exists = True, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_generate_files_with_overwrite_if_exists
test_generate_files.py::test_generate_files_with_overwrite_if_exists
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_overw1')
def test_generate_files_with_overwrite_if_exists(tmp_path):
"""Verify overwrite_if_exists overwrites old files."""
simple_file = Path(tmp_path, 'inputpizzä/simple.txt')
simple_with_new_line_file = Path(tmp_path, 'inputpizzä/simple-with-newline.txt')
Path(tmp_path, 'inputpizzä').mkdir(parents=True)
Path(simple_file).write_text('temp')
> generate.generate_files(
context={'cookiecutter': {'food': 'pizzä'}},
repo_dir='tests/test-generate-files',
overwrite_if_exists=True,
output_dir=tmp_path,
)
tests/test_generate_files.py:289:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-generate-files'
context = {'cookiecutter': {'food': 'pizzä'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_generate_files_with_overw1')
overwrite_if_exists = True, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_raise_undefined_variable_file_name
test_generate_files.py::test_raise_undefined_variable_file_name
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_0/output'
undefined_context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
def test_raise_undefined_variable_file_name(output_dir, undefined_context):
"""Verify correct error raised when file name cannot be rendered."""
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> generate.generate_files(
repo_dir='tests/undefined-variable/file-name/',
output_dir=output_dir,
context=undefined_context,
)
tests/test_generate_files.py:316:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/file-name/'
context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_0/output'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_raise_undefined_variable_file_name_existing_project
test_generate_files.py::test_raise_undefined_variable_file_name_existing_project
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_1/output'
undefined_context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
def test_raise_undefined_variable_file_name_existing_project(
output_dir, undefined_context
):
"""Verify correct error raised when file name cannot be rendered."""
testproj_path = Path(output_dir, 'testproject')
testproj_path.mkdir()
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> generate.generate_files(
repo_dir='tests/undefined-variable/file-name/',
output_dir=output_dir,
context=undefined_context,
overwrite_if_exists=True,
)
tests/test_generate_files.py:336:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/file-name/'
context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_1/output'
overwrite_if_exists = True, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_raise_undefined_variable_file_content
test_generate_files.py::test_raise_undefined_variable_file_content
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_2/output'
undefined_context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
def test_raise_undefined_variable_file_content(output_dir, undefined_context):
"""Verify correct error raised when file content cannot be rendered."""
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> generate.generate_files(
repo_dir='tests/undefined-variable/file-content/',
output_dir=output_dir,
context=undefined_context,
)
tests/test_generate_files.py:352:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/file-content/'
context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_2/output'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_raise_undefined_variable_dir_name
test_generate_files.py::test_raise_undefined_variable_dir_name
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_3/output'
undefined_context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
def test_raise_undefined_variable_dir_name(output_dir, undefined_context):
"""Verify correct error raised when directory name cannot be rendered."""
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> generate.generate_files(
repo_dir='tests/undefined-variable/dir-name/',
output_dir=output_dir,
context=undefined_context,
)
tests/test_generate_files.py:367:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/dir-name/'
context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_3/output'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_keep_project_dir_on_failure
test_generate_files.py::test_keep_project_dir_on_failure
output_dir = '/tmp/pytest-of-root/pytest-0/test_keep_project_dir_on_failu0/output'
undefined_context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
def test_keep_project_dir_on_failure(output_dir, undefined_context):
"""Verify correct error raised when directory name cannot be rendered."""
with pytest.raises(exceptions.UndefinedVariableInTemplate):
> generate.generate_files(
repo_dir='tests/undefined-variable/dir-name/',
output_dir=output_dir,
context=undefined_context,
keep_project_on_failure=True,
)
tests/test_generate_files.py:386:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/dir-name/'
context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_keep_project_dir_on_failu0/output'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = True
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_raise_undefined_variable_dir_name_existing_project
test_generate_files.py::test_raise_undefined_variable_dir_name_existing_project
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_4/output'
undefined_context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
def test_raise_undefined_variable_dir_name_existing_project(
output_dir, undefined_context
):
"""Verify correct error raised when directory name cannot be rendered."""
testproj_path = Path(output_dir, 'testproject')
testproj_path.mkdir()
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> generate.generate_files(
repo_dir='tests/undefined-variable/dir-name/',
output_dir=output_dir,
context=undefined_context,
overwrite_if_exists=True,
)
tests/test_generate_files.py:403:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/dir-name/'
context = {'cookiecutter': {'github_username': 'hackebrot', 'project_slug': 'testproject'}}
output_dir = '/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_4/output'
overwrite_if_exists = True, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_files.py::test_raise_undefined_variable_project_dir
test_generate_files.py::test_raise_undefined_variable_project_dir
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_5')
def test_raise_undefined_variable_project_dir(tmp_path):
"""Verify correct error raised when directory name cannot be rendered."""
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> generate.generate_files(
repo_dir='tests/undefined-variable/dir-name/',
output_dir=tmp_path,
context={},
)
tests/test_generate_files.py:423:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/undefined-variable/dir-name/', context = {}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_raise_undefined_variable_5')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_ignore_hooks_dirs
test_generate_hooks.py::test_ignore_hooks_dirs
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_ignore_hooks_dirs():
"""Verify hooks directory not created in target location on files generation."""
> generate.generate_files(
context={'cookiecutter': {'pyhooks': 'pyhooks'}},
repo_dir='tests/test-pyhooks/',
output_dir='tests/test-pyhooks/',
)
tests/test_generate_hooks.py:35:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-pyhooks/'
context = {'cookiecutter': {'pyhooks': 'pyhooks'}}
output_dir = 'tests/test-pyhooks/', overwrite_if_exists = False
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_run_python_hooks
test_generate_hooks.py::test_run_python_hooks
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_run_python_hooks():
"""Verify pre and post generation python hooks executed and result in output_dir.
Each hook should create in target directory. Test verifies that these files
created.
"""
> generate.generate_files(
context={'cookiecutter': {'pyhooks': 'pyhooks'}},
repo_dir='tests/test-pyhooks/',
output_dir='tests/test-pyhooks/',
)
tests/test_generate_hooks.py:50:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-pyhooks/'
context = {'cookiecutter': {'pyhooks': 'pyhooks'}}
output_dir = 'tests/test-pyhooks/', overwrite_if_exists = False
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_run_python_hooks_cwd
test_generate_hooks.py::test_run_python_hooks_cwd
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_run_python_hooks_cwd():
"""Verify pre and post generation python hooks executed and result in current dir.
Each hook should create in target directory. Test verifies that these files
created.
"""
> generate.generate_files(
context={'cookiecutter': {'pyhooks': 'pyhooks'}}, repo_dir='tests/test-pyhooks/'
)
tests/test_generate_hooks.py:66:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-pyhooks/'
context = {'cookiecutter': {'pyhooks': 'pyhooks'}}, output_dir = '.'
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_empty_hooks
test_generate_hooks.py::test_empty_hooks
@pytest.mark.skipif(WINDOWS, reason='OSError.errno=8 is not thrown on Windows')
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_empty_hooks():
"""Verify error is raised on empty hook script. Ignored on windows.
OSError.errno=8 is not thrown on Windows when the script is empty
because it always runs through shell instead of needing a shebang.
"""
with pytest.raises(FailedHookException) as excinfo:
> generate.generate_files(
context={'cookiecutter': {'shellhooks': 'shellhooks'}},
repo_dir='tests/test-shellhooks-empty/',
overwrite_if_exists=True,
)
tests/test_generate_hooks.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-shellhooks-empty/'
context = {'cookiecutter': {'shellhooks': 'shellhooks'}}, output_dir = '.'
overwrite_if_exists = True, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_oserror_hooks
test_generate_hooks.py::test_oserror_hooks
mocker =
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_oserror_hooks(mocker):
"""Verify script error passed correctly to cookiecutter error.
Here subprocess.Popen function mocked, ie we do not call hook script,
just produce expected error.
"""
message = 'Out of memory'
err = OSError(message)
err.errno = errno.ENOMEM
prompt = mocker.patch('subprocess.Popen')
prompt.side_effect = err
with pytest.raises(FailedHookException) as excinfo:
> generate.generate_files(
context={'cookiecutter': {'shellhooks': 'shellhooks'}},
repo_dir='tests/test-shellhooks-empty/',
overwrite_if_exists=True,
)
tests/test_generate_hooks.py:106:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-shellhooks-empty/'
context = {'cookiecutter': {'shellhooks': 'shellhooks'}}, output_dir = '.'
overwrite_if_exists = True, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_run_failing_hook_removes_output_directory
test_generate_hooks.py::test_run_failing_hook_removes_output_directory
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_run_failing_hook_removes_output_directory():
"""Verify project directory not created or removed if hook failed."""
repo_path = os.path.abspath('tests/test-hooks/')
hooks_path = os.path.abspath('tests/test-hooks/hooks')
hook_dir = os.path.join(repo_path, 'hooks')
template = os.path.join(repo_path, 'input{{cookiecutter.hooks}}')
> os.mkdir(repo_path)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_generate_hooks.py:122: FileExistsError
test_generate_hooks.py::test_run_failing_hook_preserves_existing_output_directory
test_generate_hooks.py::test_run_failing_hook_preserves_existing_output_directory
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_run_failing_hook_preserves_existing_output_directory():
"""Verify project directory not removed if exist before hook failed."""
repo_path = os.path.abspath('tests/test-hooks/')
hooks_path = os.path.abspath('tests/test-hooks/hooks')
hook_dir = os.path.join(repo_path, 'hooks')
template = os.path.join(repo_path, 'input{{cookiecutter.hooks}}')
> os.mkdir(repo_path)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_generate_hooks.py:151: FileExistsError
test_generate_hooks.py::test_run_shell_hooks
test_generate_hooks.py::test_run_shell_hooks
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_run_shell_hooks0')
@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux only test")
@pytest.mark.usefixtures('clean_system', 'remove_additional_folders')
def test_run_shell_hooks(tmp_path):
"""Verify pre and post generate project shell hooks executed.
This test for .sh files.
"""
> generate.generate_files(
context={'cookiecutter': {'shellhooks': 'shellhooks'}},
repo_dir='tests/test-shellhooks/',
output_dir=tmp_path.joinpath('test-shellhooks'),
)
tests/test_generate_hooks.py:180:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-shellhooks/'
context = {'cookiecutter': {'shellhooks': 'shellhooks'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_run_shell_hooks0/test-shellhooks')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_ignore_shell_hooks
test_generate_hooks.py::test_ignore_shell_hooks
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_ignore_shell_hooks0')
@pytest.mark.usefixtures("clean_system", "remove_additional_folders")
def test_ignore_shell_hooks(tmp_path):
"""Verify *.txt files not created, when accept_hooks=False."""
> generate.generate_files(
context={"cookiecutter": {"shellhooks": "shellhooks"}},
repo_dir="tests/test-shellhooks/",
output_dir=tmp_path.joinpath('test-shellhooks'),
accept_hooks=False,
)
tests/test_generate_hooks.py:220:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-shellhooks/'
context = {'cookiecutter': {'shellhooks': 'shellhooks'}}
output_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_ignore_shell_hooks0/test-shellhooks')
overwrite_if_exists = False, skip_if_file_exists = False, accept_hooks = False
keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_generate_hooks.py::test_deprecate_run_hook_from_repo_dir
test_generate_hooks.py::test_deprecate_run_hook_from_repo_dir
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_deprecate_run_hook_from_r0')
@pytest.mark.usefixtures("clean_system", "remove_additional_folders")
def test_deprecate_run_hook_from_repo_dir(tmp_path):
"""Test deprecation warning in generate._run_hook_from_repo_dir."""
repo_dir = "tests/test-shellhooks/"
project_dir = Path(tmp_path.joinpath('test-shellhooks'))
project_dir.mkdir()
with pytest.deprecated_call():
> generate._run_hook_from_repo_dir(
repo_dir=repo_dir,
hook_name="pre_gen_project",
project_dir=project_dir,
context={},
delete_project_on_failure=False,
)
tests/test_generate_hooks.py:241:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/generate.py:179: in _run_hook_from_repo_dir
with work_in(repo_dir):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
def __enter__(self):
# do not keep args and kwds alive unnecessarily
# they are only needed for recreation, which is not possible anymore
del self.args, self.kwds, self.func
try:
> return next(self.gen)
E TypeError: 'NoneType' object is not an iterator
/usr/lib/python3.10/contextlib.py:135: TypeError
During handling of the above exception, another exception occurred:
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_deprecate_run_hook_from_r0')
@pytest.mark.usefixtures("clean_system", "remove_additional_folders")
def test_deprecate_run_hook_from_repo_dir(tmp_path):
"""Test deprecation warning in generate._run_hook_from_repo_dir."""
repo_dir = "tests/test-shellhooks/"
project_dir = Path(tmp_path.joinpath('test-shellhooks'))
project_dir.mkdir()
> with pytest.deprecated_call():
E Failed: DID NOT WARN. No warnings of type (, , ) were emitted.
E Emitted warnings: [].
tests/test_generate_hooks.py:240: Failed
test_get_config.py::test_merge_configs
test_get_config.py::test_merge_configs
def test_merge_configs():
"""Verify default and user config merged in expected way."""
default = {
'cookiecutters_dir': '/home/example/some-path-to-templates',
'replay_dir': '/home/example/some-path-to-replay-files',
'default_context': {},
'abbreviations': {
'gh': 'https://github.com/{0}.git',
'gl': 'https://gitlab.com/{0}.git',
'bb': 'https://bitbucket.org/{0}',
},
}
user_config = {
'default_context': {
'full_name': 'Raphael Pierzina',
'github_username': 'hackebrot',
},
'abbreviations': {
'gl': 'https://gitlab.com/hackebrot/{0}.git',
'pytest-plugin': 'https://github.com/pytest-dev/pytest-plugin.git',
},
}
expected_config = {
'cookiecutters_dir': '/home/example/some-path-to-templates',
'replay_dir': '/home/example/some-path-to-replay-files',
'default_context': {
'full_name': 'Raphael Pierzina',
'github_username': 'hackebrot',
},
'abbreviations': {
'gh': 'https://github.com/{0}.git',
'gl': 'https://gitlab.com/hackebrot/{0}.git',
'bb': 'https://bitbucket.org/{0}',
'pytest-plugin': 'https://github.com/pytest-dev/pytest-plugin.git',
},
}
> assert config.merge_configs(default, user_config) == expected_config
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/hackebrot/{0}.git', 'pytest-plugin': 'https://github.com/pytest-dev/pytest-plugin.git'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'full_name': 'Raphael Pierzina', 'github_username': 'hackebrot'}, 'replay_dir': '/home/example/some-path-to-replay-files'}
E + where None = ({'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {}, 'replay_dir': '/home/example/some-path-to-replay-files'}, {'abbreviations': {'gl': 'https://gitlab.com/hackebrot/{0}.git', 'pytest-plugin': 'https://github.com/pytest-dev/pytest-plugin.git'}, 'default_context': {'full_name': 'Raphael Pierzina', 'github_username': 'hackebrot'}})
E + where = config.merge_configs
tests/test_get_config.py:51: AssertionError
test_get_config.py::test_get_config
test_get_config.py::test_get_config
def test_get_config():
"""Verify valid config opened and rendered correctly."""
conf = config.get_config('tests/test-config/valid-config.yaml')
expected_conf = {
'cookiecutters_dir': '/home/example/some-path-to-templates',
'replay_dir': '/home/example/some-path-to-replay-files',
'default_context': {
'full_name': 'Firstname Lastname',
'email': 'firstname.lastname@gmail.com',
'github_username': 'example',
'project': {
'description': 'description',
'tags': [
'first',
'second',
'third',
],
},
},
'abbreviations': {
'gh': 'https://github.com/{0}.git',
'gl': 'https://gitlab.com/{0}.git',
'bb': 'https://bitbucket.org/{0}',
'helloworld': 'https://github.com/hackebrot/helloworld',
},
}
> assert conf == expected_conf
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git', 'helloworld': 'https://github.com/hackebrot/helloworld'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example', 'project': {'description': 'description', 'tags': ['first', 'second', 'third']}}, 'replay_dir': '/home/example/some-path-to-replay-files'}
tests/test_get_config.py:80: AssertionError
test_get_config.py::test_get_config_does_not_exist
test_get_config.py::test_get_config_does_not_exist
def test_get_config_does_not_exist():
"""Check that `exceptions.ConfigDoesNotExistException` is raised when \
attempting to get a non-existent config file."""
expected_error_msg = 'Config file tests/not-exist.yaml does not exist.'
> with pytest.raises(ConfigDoesNotExistException) as exc_info:
E Failed: DID NOT RAISE
tests/test_get_config.py:87: Failed
test_get_config.py::test_invalid_config
test_get_config.py::test_invalid_config
def test_invalid_config():
"""An invalid config file should raise an `InvalidConfiguration` \
exception."""
expected_error_msg = (
'Unable to parse YAML file tests/test-config/invalid-config.yaml.'
)
with pytest.raises(InvalidConfiguration) as exc_info:
config.get_config('tests/test-config/invalid-config.yaml')
> assert expected_error_msg in str(exc_info.value)
tests/test_get_config.py:100:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
@property
def value(self) -> E:
"""The exception value."""
assert (
> self._excinfo is not None
), ".value can only be used after the context manager exits"
E AssertionError: .value can only be used after the context manager exits
.venv/lib/python3.10/site-packages/_pytest/_code/code.py:548: AssertionError
test_get_config.py::test_get_config_with_defaults
test_get_config.py::test_get_config_with_defaults
def test_get_config_with_defaults():
"""A config file that overrides 1 of 3 defaults."""
conf = config.get_config('tests/test-config/valid-partial-config.yaml')
default_cookiecutters_dir = Path('~/.cookiecutters').expanduser()
default_replay_dir = Path('~/.cookiecutter_replay').expanduser()
expected_conf = {
'cookiecutters_dir': str(default_cookiecutters_dir),
'replay_dir': str(default_replay_dir),
'default_context': {
'full_name': 'Firstname Lastname',
'email': 'firstname.lastname@gmail.com',
'github_username': 'example',
},
'abbreviations': {
'gh': 'https://github.com/{0}.git',
'gl': 'https://gitlab.com/{0}.git',
'bb': 'https://bitbucket.org/{0}',
},
}
> assert conf == expected_conf
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_get_config_with_defaults0/home/.cookiecutters', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example'}, 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_get_config_with_defaults0/home/.cookiecutter_replay'}
tests/test_get_config.py:123: AssertionError
test_get_config.py::test_get_config_empty_config_file
test_get_config.py::test_get_config_empty_config_file
def test_get_config_empty_config_file():
"""An empty config file results in the default config."""
conf = config.get_config('tests/test-config/empty-config.yaml')
> assert conf == config.DEFAULT_CONFIG
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_get_config_empty_config_f0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_get_config_empty_config_f0/home/.cookiecutter_replay'}
E + where {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_get_config_empty_config_f0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_get_config_empty_config_f0/home/.cookiecutter_replay'} = config.DEFAULT_CONFIG
tests/test_get_config.py:129: AssertionError
test_get_config.py::test_get_config_invalid_file_with_array_as_top_level_element
test_get_config.py::test_get_config_invalid_file_with_array_as_top_level_element
def test_get_config_invalid_file_with_array_as_top_level_element():
"""An exception should be raised if top-level element is array."""
expected_error_msg = (
'Top-level element of YAML file '
'tests/test-config/invalid-config-w-array.yaml should be an object.'
)
> with pytest.raises(InvalidConfiguration) as exc_info:
E Failed: DID NOT RAISE
tests/test_get_config.py:138: Failed
test_get_config.py::test_get_config_invalid_file_with_multiple_docs
test_get_config.py::test_get_config_invalid_file_with_multiple_docs
def test_get_config_invalid_file_with_multiple_docs():
"""An exception should be raised if config file contains multiple docs."""
expected_error_msg = (
'Unable to parse YAML file '
'tests/test-config/invalid-config-w-multiple-docs.yaml.'
)
> with pytest.raises(InvalidConfiguration) as exc_info:
E Failed: DID NOT RAISE
tests/test_get_config.py:149: Failed
test_get_user_config.py::test_get_user_config_valid
test_get_user_config.py::test_get_user_config_valid
user_config_path = '/root/.cookiecutterrc'
custom_config = {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git', 'helloworld': 'https://github.com/hackebrot/helloworld'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example', 'project': {'description': 'description', 'tags': ['first', 'second', 'third']}}, 'replay_dir': '/home/example/some-path-to-replay-files'}
@pytest.mark.usefixtures('back_up_rc')
def test_get_user_config_valid(user_config_path, custom_config):
"""Validate user config correctly parsed if exist and correctly formatted."""
shutil.copy('tests/test-config/valid-config.yaml', user_config_path)
conf = config.get_user_config()
> assert conf == custom_config
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git', 'helloworld': 'https://github.com/hackebrot/helloworld'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example', 'project': {'description': 'description', 'tags': ['first', 'second', 'third']}}, 'replay_dir': '/home/example/some-path-to-replay-files'}
tests/test_get_user_config.py:76: AssertionError
test_get_user_config.py::test_get_user_config_invalid
test_get_user_config.py::test_get_user_config_invalid
user_config_path = '/root/.cookiecutterrc'
@pytest.mark.usefixtures('back_up_rc')
def test_get_user_config_invalid(user_config_path):
"""Validate `InvalidConfiguration` raised when provided user config malformed."""
shutil.copy('tests/test-config/invalid-config.yaml', user_config_path)
> with pytest.raises(InvalidConfiguration):
E Failed: DID NOT RAISE
tests/test_get_user_config.py:83: Failed
test_get_user_config.py::test_get_user_config_nonexistent
test_get_user_config.py::test_get_user_config_nonexistent
@pytest.mark.usefixtures('back_up_rc')
def test_get_user_config_nonexistent():
"""Validate default app config returned, if user does not have own config."""
> assert config.get_user_config() == config.DEFAULT_CONFIG
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_get_user_config_nonexiste0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_get_user_config_nonexiste0/home/.cookiecutter_replay'}
E + where None = ()
E + where = config.get_user_config
E + and {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_get_user_config_nonexiste0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_get_user_config_nonexiste0/home/.cookiecutter_replay'} = config.DEFAULT_CONFIG
tests/test_get_user_config.py:90: AssertionError
test_get_user_config.py::test_specify_config_path
test_get_user_config.py::test_specify_config_path
self =
args = ('tests/test-config/valid-config.yaml',), kwargs = {}
msg = "Expected 'get_config' to be called once. Called 0 times."
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
> raise AssertionError(msg)
E AssertionError: Expected 'get_config' to be called once. Called 0 times.
/usr/lib/python3.10/unittest/mock.py:940: AssertionError
During handling of the above exception, another exception occurred:
mocker =
custom_config_path = 'tests/test-config/valid-config.yaml'
custom_config = {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git', 'helloworld': 'https://github.com/hackebrot/helloworld'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example', 'project': {'description': 'description', 'tags': ['first', 'second', 'third']}}, 'replay_dir': '/home/example/some-path-to-replay-files'}
def test_specify_config_path(mocker, custom_config_path, custom_config):
"""Validate provided custom config path should be respected and parsed."""
spy_get_config = mocker.spy(config, 'get_config')
user_config = config.get_user_config(custom_config_path)
> spy_get_config.assert_called_once_with(custom_config_path)
tests/test_get_user_config.py:104:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = ('tests/test-config/valid-config.yaml',), kwargs = {}
def assert_called_once_with(*args, **kwargs):
> return mock.assert_called_once_with(*args, **kwargs)
E AssertionError: Expected 'get_config' to be called once. Called 0 times.
/usr/lib/python3.10/unittest/mock.py:213: AssertionError
test_get_user_config.py::test_default_config_from_env_variable
test_get_user_config.py::test_default_config_from_env_variable
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f9a1390>
custom_config_path = 'tests/test-config/valid-config.yaml'
custom_config = {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git', 'helloworld': 'https://github.com/hackebrot/helloworld'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example', 'project': {'description': 'description', 'tags': ['first', 'second', 'third']}}, 'replay_dir': '/home/example/some-path-to-replay-files'}
def test_default_config_from_env_variable(
monkeypatch, custom_config_path, custom_config
):
"""Validate app configuration. User config path should be parsed from sys env."""
monkeypatch.setenv('COOKIECUTTER_CONFIG', custom_config_path)
user_config = config.get_user_config()
> assert user_config == custom_config
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git', 'helloworld': 'https://github.com/hackebrot/helloworld'}, 'cookiecutters_dir': '/home/example/some-path-to-templates', 'default_context': {'email': 'firstname.lastname@gmail.com', 'full_name': 'Firstname Lastname', 'github_username': 'example', 'project': {'description': 'description', 'tags': ['first', 'second', 'third']}}, 'replay_dir': '/home/example/some-path-to-replay-files'}
tests/test_get_user_config.py:121: AssertionError
test_get_user_config.py::test_force_default_config
test_get_user_config.py::test_force_default_config
mocker =
custom_config_path = 'tests/test-config/valid-config.yaml'
def test_force_default_config(mocker, custom_config_path):
"""Validate `default_config=True` should ignore provided custom user config."""
spy_get_config = mocker.spy(config, 'get_config')
user_config = config.get_user_config(custom_config_path, default_config=True)
> assert user_config == config.DEFAULT_CONFIG
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_force_default_config0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_force_default_config0/home/.cookiecutter_replay'}
E + where {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_force_default_config0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': '/tmp/pytest-of-root/pytest-0/test_force_default_config0/home/.cookiecutter_replay'} = config.DEFAULT_CONFIG
tests/test_get_user_config.py:130: AssertionError
test_get_user_config.py::test_expand_user_for_directories_in_config
test_get_user_config.py::test_expand_user_for_directories_in_config
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f44ba00>
def test_expand_user_for_directories_in_config(monkeypatch):
"""Validate user pointers expanded in user configs."""
def _expanduser(path):
return path.replace('~', 'Users/bob')
monkeypatch.setattr('os.path.expanduser', _expanduser)
config_file = 'tests/test-config/config-expand-user.yaml'
user_config = config.get_user_config(config_file)
> assert user_config['replay_dir'] == 'Users/bob/replay-files'
E TypeError: 'NoneType' object is not subscriptable
tests/test_get_user_config.py:145: TypeError
test_get_user_config.py::test_expand_vars_for_directories_in_config
test_get_user_config.py::test_expand_vars_for_directories_in_config
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fe680a0>
def test_expand_vars_for_directories_in_config(monkeypatch):
"""Validate environment variables expanded in user configs."""
monkeypatch.setenv('COOKIES', 'Users/bob/cookies')
config_file = 'tests/test-config/config-expand-vars.yaml'
user_config = config.get_user_config(config_file)
> assert user_config['replay_dir'] == 'Users/bob/cookies/replay-files'
E TypeError: 'NoneType' object is not subscriptable
tests/test_get_user_config.py:156: TypeError
test_get_user_config.py::test_specify_config_values
test_get_user_config.py::test_specify_config_values
def test_specify_config_values():
"""Validate provided custom config values should be respected."""
replay_dir = 'Users/bob/cookies/custom-replay-dir'
custom_config_updated = {**config.DEFAULT_CONFIG, 'replay_dir': replay_dir}
user_config = config.get_user_config(default_config={'replay_dir': replay_dir})
> assert user_config == custom_config_updated
E AssertionError: assert None == {'abbreviations': {'bb': 'https://bitbucket.org/{0}', 'gh': 'https://github.com/{0}.git', 'gl': 'https://gitlab.com/{0}.git'}, 'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/test_specify_config_values0/home/.cookiecutters', 'default_context': OrderedDict(), 'replay_dir': 'Users/bob/cookies/custom-replay-dir'}
tests/test_get_user_config.py:167: AssertionError
test_hooks.py::TestFindHooks::test_find_hook
test_hooks.py::TestFindHooks::test_find_hook
self =
method = >
def setup_method(self, method):
"""Find hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path)
tests/test_hooks.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'tests/test-hooks', multiple_hooks = False
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: 'tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestFindHooks::test_no_hooks
test_hooks.py::TestFindHooks::test_no_hooks
self =
method = >
def setup_method(self, method):
"""Find hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path)
tests/test_hooks.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'tests/test-hooks', multiple_hooks = False
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: 'tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestFindHooks::test_unknown_hooks_dir
test_hooks.py::TestFindHooks::test_unknown_hooks_dir
self =
method = >
def setup_method(self, method):
"""Find hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path)
tests/test_hooks.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'tests/test-hooks', multiple_hooks = False
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: 'tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestFindHooks::test_hook_not_found
test_hooks.py::TestFindHooks::test_hook_not_found
self =
method = >
def setup_method(self, method):
"""Find hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path)
tests/test_hooks.py:82:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'tests/test-hooks', multiple_hooks = False
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: 'tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_script
test_hooks.py::TestExternalHooks::test_run_script
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_failing_script
test_hooks.py::TestExternalHooks::test_run_failing_script
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_failing_script_enoexec
test_hooks.py::TestExternalHooks::test_run_failing_script_enoexec
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_script_cwd
test_hooks.py::TestExternalHooks::test_run_script_cwd
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_script_with_context
test_hooks.py::TestExternalHooks::test_run_script_with_context
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_hook
test_hooks.py::TestExternalHooks::test_run_hook
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::TestExternalHooks::test_run_failing_hook
test_hooks.py::TestExternalHooks::test_run_failing_hook
self =
method = >
def setup_method(self, method):
"""External hooks related tests setup fixture."""
> self.post_hook = make_test_repo(self.repo_path, multiple_hooks=True)
tests/test_hooks.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = '/testbed/tests/test-hooks', multiple_hooks = True
def make_test_repo(name, multiple_hooks=False):
"""Create test repository for test setup methods."""
hook_dir = os.path.join(name, 'hooks')
template = os.path.join(name, 'input{{hooks}}')
> os.mkdir(name)
E FileExistsError: [Errno 17] File exists: '/testbed/tests/test-hooks'
tests/test_hooks.py:19: FileExistsError
test_hooks.py::test_ignore_hook_backup_files
test_hooks.py::test_ignore_hook_backup_files
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fa67370>
dir_with_hooks = '/tmp/pytest-of-root/pytest-0/test_ignore_hook_backup_files0'
def test_ignore_hook_backup_files(monkeypatch, dir_with_hooks):
"""Test `find_hook` correctly use `valid_hook` verification function."""
# Change the current working directory that contains `hooks/`
monkeypatch.chdir(dir_with_hooks)
> assert hooks.find_hook('pre_gen_project') is None
E AssertionError: assert '/tmp/pytest-of-root/pytest-0/test_ignore_hook_backup_files0/hooks/pre_gen_project.py~' is None
E + where '/tmp/pytest-of-root/pytest-0/test_ignore_hook_backup_files0/hooks/pre_gen_project.py~' = ('pre_gen_project')
E + where = hooks.find_hook
/testbed/tests/test_hooks.py:274: AssertionError
test_log.py::test_info_stdout_logging
test_log.py::test_info_stdout_logging
caplog = <_pytest.logging.LogCaptureFixture object at 0x7f6a6fb5e320>
info_logger = None
info_messages = ['INFO: Welcome to Cookiecutter', 'INFO: Loading user config from home dir', 'ERROR: Aw, snap! Something went wrong']
def test_info_stdout_logging(caplog, info_logger, info_messages):
"""Test that stdout logs use info format and level."""
> [stream_handler] = info_logger.handlers
E AttributeError: 'NoneType' object has no attribute 'handlers'
tests/test_log.py:75: AttributeError
test_log.py::test_debug_stdout_logging
test_log.py::test_debug_stdout_logging
caplog = <_pytest.logging.LogCaptureFixture object at 0x7f6a6fc01810>
debug_logger = None
debug_messages = ['INFO cookiecutter: Welcome to Cookiecutter', 'DEBUG cookiecutter: Generating project from pytest-plugin', 'INFO cookiecutter.foo: Loading user config from home dir', "DEBUG cookiecutter.foo.bar: I don't know.", 'DEBUG cookiecutter.foo.bar: I wanted to save the world.', 'ERROR cookiecutter.foo: Aw, snap! Something went wrong', ...]
def test_debug_stdout_logging(caplog, debug_logger, debug_messages):
"""Test that stdout logs use debug format and level."""
> [stream_handler] = debug_logger.handlers
E AttributeError: 'NoneType' object has no attribute 'handlers'
tests/test_log.py:92: AttributeError
test_log.py::test_debug_file_logging
test_log.py::test_debug_file_logging
caplog = <_pytest.logging.LogCaptureFixture object at 0x7f6a6fb5efb0>
info_logger_with_file = None
debug_file = PosixPath('/tmp/pytest-of-root/pytest-0/test_debug_file_logging0/pytest-plugin.log')
debug_messages = ['INFO cookiecutter: Welcome to Cookiecutter', 'DEBUG cookiecutter: Generating project from pytest-plugin', 'INFO cookiecutter.foo: Loading user config from home dir', "DEBUG cookiecutter.foo.bar: I don't know.", 'DEBUG cookiecutter.foo.bar: I wanted to save the world.', 'ERROR cookiecutter.foo: Aw, snap! Something went wrong', ...]
def test_debug_file_logging(caplog, info_logger_with_file, debug_file, debug_messages):
"""Test that logging to stdout uses a different format and level than \
the the file handler."""
> [file_handler, stream_handler] = info_logger_with_file.handlers
E AttributeError: 'NoneType' object has no attribute 'handlers'
tests/test_log.py:110: AttributeError
test_main.py::test_original_cookiecutter_options_preserved_in__cookiecutter
test_main.py::test_original_cookiecutter_options_preserved_in__cookiecutter
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fc03b20>
mocker =
user_config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
def test_original_cookiecutter_options_preserved_in__cookiecutter(
monkeypatch,
mocker,
user_config_file,
):
"""Preserve original context options.
Tests you can access the original context options via
`context['_cookiecutter']`.
"""
monkeypatch.chdir('tests/fake-repo-tmpl-_cookiecutter')
mock_generate_files = mocker.patch('cookiecutter.main.generate_files')
> cookiecutter(
'.',
no_input=True,
replay=False,
config_file=user_config_file,
)
/testbed/tests/test_main.py:18:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '.', checkout = None, no_input = True, extra_context = None
replay = False, overwrite_if_exists = False, output_dir = '.'
config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
/testbed/cookiecutter/main.py:65: TypeError
test_main.py::test_replay_dump_template_name
test_main.py::test_replay_dump_template_name
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f6a5ba0>
mocker =
user_config_data = {'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters', 'replay_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutter_replay'}
user_config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
def test_replay_dump_template_name(
monkeypatch, mocker, user_config_data, user_config_file
):
"""Check that replay_dump is called with a valid template_name.
Template name must not be a relative path.
Otherwise files such as ``..json`` are created, which are not just cryptic
but also later mistaken for replay files of other templates if invoked with
'.' and '--replay'.
Change the current working directory temporarily to 'tests/fake-repo-tmpl'
for this test and call cookiecutter with '.' for the target template.
"""
monkeypatch.chdir('tests/fake-repo-tmpl')
mock_replay_dump = mocker.patch('cookiecutter.main.dump')
mocker.patch('cookiecutter.main.generate_files')
> cookiecutter(
'.',
no_input=True,
replay=False,
config_file=user_config_file,
)
/testbed/tests/test_main.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '.', checkout = None, no_input = True, extra_context = None
replay = False, overwrite_if_exists = False, output_dir = '.'
config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
/testbed/cookiecutter/main.py:65: TypeError
test_main.py::test_replay_load_template_name
test_main.py::test_replay_load_template_name
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fb3ad10>
mocker =
user_config_data = {'cookiecutters_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutters', 'replay_dir': '/tmp/pytest-of-root/pytest-0/user_dir0/cookiecutter_replay'}
user_config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
def test_replay_load_template_name(
monkeypatch, mocker, user_config_data, user_config_file
):
"""Check that replay_load is called correctly.
Calls require valid template_name that is not a relative path.
Change the current working directory temporarily to 'tests/fake-repo-tmpl'
for this test and call cookiecutter with '.' for the target template.
"""
monkeypatch.chdir('tests/fake-repo-tmpl')
mock_replay_load = mocker.patch('cookiecutter.main.load')
mocker.patch('cookiecutter.main.generate_context').return_value = {
'cookiecutter': {}
}
mocker.patch('cookiecutter.main.generate_files')
mocker.patch('cookiecutter.main.dump')
> cookiecutter(
'.',
replay=True,
config_file=user_config_file,
)
/testbed/tests/test_main.py:84:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '.', checkout = None, no_input = False, extra_context = None
replay = True, overwrite_if_exists = False, output_dir = '.'
config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
/testbed/cookiecutter/main.py:65: TypeError
test_main.py::test_custom_replay_file
test_main.py::test_custom_replay_file
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f9a1bd0>
mocker =
user_config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
def test_custom_replay_file(monkeypatch, mocker, user_config_file):
"""Check that reply.load is called with the custom replay_file."""
monkeypatch.chdir('tests/fake-repo-tmpl')
mock_replay_load = mocker.patch('cookiecutter.main.load')
mocker.patch('cookiecutter.main.generate_context').return_value = {
'cookiecutter': {}
}
mocker.patch('cookiecutter.main.generate_files')
mocker.patch('cookiecutter.main.dump')
> cookiecutter(
'.',
replay='./custom-replay-file',
config_file=user_config_file,
)
/testbed/tests/test_main.py:107:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '.', checkout = None, no_input = False, extra_context = None
replay = './custom-replay-file', overwrite_if_exists = False, output_dir = '.'
config_file = '/tmp/pytest-of-root/pytest-0/user_dir0/config'
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
/testbed/cookiecutter/main.py:65: TypeError
test_output_folder.py::test_output_folder
test_output_folder.py::test_output_folder
@pytest.mark.usefixtures('clean_system', 'remove_output_folder')
def test_output_folder():
"""Tests should correctly create content, as output_folder does not yet exist."""
context = generate.generate_context(
context_file='tests/test-output-folder/cookiecutter.json'
)
> generate.generate_files(context=context, repo_dir='tests/test-output-folder')
tests/test_output_folder.py:30:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-output-folder'
context = {'cookiecutter': OrderedDict([('full_name', 'Audrey Greenfeld'), ('year', '2014'), ('color', 'green'), ('letter', 'D'), ('folder_name', 'im_a.dir'), ('filename', 'im_a.file'), ('test_name', 'output_folder')])}
output_dir = '.', overwrite_if_exists = False, skip_if_file_exists = False
accept_hooks = True, keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_output_folder.py::test_exception_when_output_folder_exists
test_output_folder.py::test_exception_when_output_folder_exists
@pytest.mark.usefixtures('clean_system', 'remove_output_folder')
def test_exception_when_output_folder_exists():
"""Tests should raise error as output folder created before `generate_files`."""
context = generate.generate_context(
context_file='tests/test-output-folder/cookiecutter.json'
)
output_folder = context['cookiecutter']['test_name']
if not os.path.exists(output_folder):
os.makedirs(output_folder)
with pytest.raises(exceptions.OutputDirExistsException):
> generate.generate_files(context=context, repo_dir='tests/test-output-folder')
tests/test_output_folder.py:58:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-output-folder'
context = {'cookiecutter': OrderedDict([('full_name', 'Audrey Greenfeld'), ('year', '2014'), ('color', 'green'), ('letter', 'D'), ('folder_name', 'im_a.dir'), ('filename', 'im_a.file'), ('test_name', 'output_folder')])}
output_dir = '.', overwrite_if_exists = False, skip_if_file_exists = False
accept_hooks = True, keep_project_on_failure = False
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
:param repo_dir: Project template input directory.
:param context: Dict for populating the template's variables.
:param output_dir: Where to output the generated project dir into.
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
context = context or {}
env = create_env_with_context(context)
> template_dir = find_template(repo_dir)
E TypeError: find_template() missing 1 required positional argument: 'env'
cookiecutter/generate.py:213: TypeError
test_pre_prompt_hooks.py::test_run_pre_prompt_python_hook
test_pre_prompt_hooks.py::test_run_pre_prompt_python_hook
remove_tmp_repo_dir = ._func at 0x7f6a6f334310>
def test_run_pre_prompt_python_hook(remove_tmp_repo_dir):
"""Verify pre_prompt.py runs and creates a copy of cookiecutter.json."""
> new_repo_dir = hooks.run_pre_prompt_hook(repo_dir='tests/test-pyhooks/')
tests/test_pre_prompt_hooks.py:27:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-pyhooks/'
def run_pre_prompt_hook(repo_dir: 'os.PathLike[str]') -> Path:
"""Run pre_prompt hook from repo directory.
:param repo_dir: Project template input directory.
"""
# Create a temporary directory for the pre-prompt hook
> temp_dir = create_tmp_repo_dir()
E TypeError: create_tmp_repo_dir() missing 1 required positional argument: 'repo_dir'
cookiecutter/hooks.py:169: TypeError
test_pre_prompt_hooks.py::test_run_pre_prompt_python_hook_fail
test_pre_prompt_hooks.py::test_run_pre_prompt_python_hook_fail
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f9b0ac0>
def test_run_pre_prompt_python_hook_fail(monkeypatch):
"""Verify pre_prompt.py will fail when a given env var is present."""
message = 'Pre-Prompt Hook script failed'
with monkeypatch.context() as m:
m.setenv('COOKIECUTTER_FAIL_PRE_PROMPT', '1')
with pytest.raises(FailedHookException) as excinfo:
> hooks.run_pre_prompt_hook(repo_dir='tests/test-pyhooks/')
tests/test_pre_prompt_hooks.py:40:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-pyhooks/'
def run_pre_prompt_hook(repo_dir: 'os.PathLike[str]') -> Path:
"""Run pre_prompt hook from repo directory.
:param repo_dir: Project template input directory.
"""
# Create a temporary directory for the pre-prompt hook
> temp_dir = create_tmp_repo_dir()
E TypeError: create_tmp_repo_dir() missing 1 required positional argument: 'repo_dir'
cookiecutter/hooks.py:169: TypeError
test_pre_prompt_hooks.py::test_run_pre_prompt_shell_hook
test_pre_prompt_hooks.py::test_run_pre_prompt_shell_hook
remove_tmp_repo_dir = ._func at 0x7f6a6f1aed40>
@pytest.mark.skipif(WINDOWS, reason='shell script will not run in Windows')
def test_run_pre_prompt_shell_hook(remove_tmp_repo_dir):
"""Verify pre_prompt.sh runs and creates a copy of cookiecutter.json."""
> new_repo_dir = hooks.run_pre_prompt_hook(repo_dir='tests/test-pyshellhooks/')
tests/test_pre_prompt_hooks.py:47:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_dir = 'tests/test-pyshellhooks/'
def run_pre_prompt_hook(repo_dir: 'os.PathLike[str]') -> Path:
"""Run pre_prompt hook from repo directory.
:param repo_dir: Project template input directory.
"""
# Create a temporary directory for the pre-prompt hook
> temp_dir = create_tmp_repo_dir()
E TypeError: create_tmp_repo_dir() missing 1 required positional argument: 'repo_dir'
cookiecutter/hooks.py:169: TypeError
test_prompt.py::TestRenderVariable::test_convert_to_str[1-1]
test_prompt.py::TestRenderVariable::test_convert_to_str[1-1]
self =
mocker =
raw_var = 1, rendered_var = '1'
@pytest.mark.parametrize(
'raw_var, rendered_var',
[
(1, '1'),
(True, True),
('foo', 'foo'),
('{{cookiecutter.project}}', 'foobar'),
(None, None),
],
)
def test_convert_to_str(self, mocker, raw_var, rendered_var):
"""Verify simple items correctly rendered to strings."""
env = environment.StrictEnvironment()
from_string = mocker.patch(
'cookiecutter.utils.StrictEnvironment.from_string', wraps=env.from_string
)
context = {'project': 'foobar'}
result = prompt.render_variable(env, raw_var, context)
> assert result == rendered_var
E AssertionError: assert 1 == '1'
tests/test_prompt.py:44: AssertionError
test_prompt.py::TestRenderVariable::test_convert_to_str[{{cookiecutter.project}}-foobar]
test_prompt.py::TestRenderVariable::test_convert_to_str[{{cookiecutter.project}}-foobar]
self =
mocker =
raw_var = '{{cookiecutter.project}}', rendered_var = 'foobar'
@pytest.mark.parametrize(
'raw_var, rendered_var',
[
(1, '1'),
(True, True),
('foo', 'foo'),
('{{cookiecutter.project}}', 'foobar'),
(None, None),
],
)
def test_convert_to_str(self, mocker, raw_var, rendered_var):
"""Verify simple items correctly rendered to strings."""
env = environment.StrictEnvironment()
from_string = mocker.patch(
'cookiecutter.utils.StrictEnvironment.from_string', wraps=env.from_string
)
context = {'project': 'foobar'}
> result = prompt.render_variable(env, raw_var, context)
tests/test_prompt.py:43:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:162: in render_variable
rendered = template.render(**cookiecutter_dict)
.venv/lib/python3.10/site-packages/jinja2/environment.py:1304: in render
self.environment.handle_exception()
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
:1: in top-level template code
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
obj = Undefined, attribute = 'project'
def getattr(self, obj: t.Any, attribute: str) -> t.Any:
"""Get an item or attribute of an object but prefer the attribute.
Unlike :meth:`getitem` the attribute *must* be a string.
"""
try:
> return getattr(obj, attribute)
E jinja2.exceptions.UndefinedError: 'cookiecutter' is undefined
.venv/lib/python3.10/site-packages/jinja2/environment.py:487: UndefinedError
test_prompt.py::TestRenderVariable::test_convert_to_str_complex_variables[raw_var0-rendered_var0]
test_prompt.py::TestRenderVariable::test_convert_to_str_complex_variables[raw_var0-rendered_var0]
self =
raw_var = {1: True, 'foo': False}, rendered_var = {'1': True, 'foo': False}
@pytest.mark.parametrize(
'raw_var, rendered_var',
[
({1: True, 'foo': False}, {'1': True, 'foo': False}),
(
{'{{cookiecutter.project}}': ['foo', 1], 'bar': False},
{'foobar': ['foo', '1'], 'bar': False},
),
(['foo', '{{cookiecutter.project}}', None], ['foo', 'foobar', None]),
],
)
def test_convert_to_str_complex_variables(self, raw_var, rendered_var):
"""Verify tree items correctly rendered."""
env = environment.StrictEnvironment()
context = {'project': 'foobar'}
result = prompt.render_variable(env, raw_var, context)
> assert result == rendered_var
E AssertionError: assert {1: True, 'foo': False} == {'1': True, 'foo': False}
E
E Common items:
E {'foo': False}
E Left contains 1 more item:
E {1: True}
E Right contains 1 more item:
E {'1': True}
E
E Full diff:
E {
E - '1': True,
E ? - -
E + 1: True,
E 'foo': False,
E }
tests/test_prompt.py:71: AssertionError
test_prompt.py::TestRenderVariable::test_convert_to_str_complex_variables[raw_var1-rendered_var1]
test_prompt.py::TestRenderVariable::test_convert_to_str_complex_variables[raw_var1-rendered_var1]
self =
raw_var = {'bar': False, '{{cookiecutter.project}}': ['foo', 1]}
rendered_var = {'bar': False, 'foobar': ['foo', '1']}
@pytest.mark.parametrize(
'raw_var, rendered_var',
[
({1: True, 'foo': False}, {'1': True, 'foo': False}),
(
{'{{cookiecutter.project}}': ['foo', 1], 'bar': False},
{'foobar': ['foo', '1'], 'bar': False},
),
(['foo', '{{cookiecutter.project}}', None], ['foo', 'foobar', None]),
],
)
def test_convert_to_str_complex_variables(self, raw_var, rendered_var):
"""Verify tree items correctly rendered."""
env = environment.StrictEnvironment()
context = {'project': 'foobar'}
result = prompt.render_variable(env, raw_var, context)
> assert result == rendered_var
E AssertionError: assert {'{{cookiecutter.project}}': ['foo', 1], 'bar': False} == {'foobar': ['foo', '1'], 'bar': False}
E
E Common items:
E {'bar': False}
E Left contains 1 more item:
E {'{{cookiecutter.project}}': ['foo', 1]}
E Right contains 1 more item:
E {'foobar': ['foo', '1']}
E
E Full diff:
E {
E 'bar': False,
E - 'foobar': [
E + '{{cookiecutter.project}}': [
E 'foo',
E - '1',
E ? - -
E + 1,
E ],
E }
tests/test_prompt.py:71: AssertionError
test_prompt.py::TestRenderVariable::test_convert_to_str_complex_variables[raw_var2-rendered_var2]
test_prompt.py::TestRenderVariable::test_convert_to_str_complex_variables[raw_var2-rendered_var2]
self =
raw_var = ['foo', '{{cookiecutter.project}}', None]
rendered_var = ['foo', 'foobar', None]
@pytest.mark.parametrize(
'raw_var, rendered_var',
[
({1: True, 'foo': False}, {'1': True, 'foo': False}),
(
{'{{cookiecutter.project}}': ['foo', 1], 'bar': False},
{'foobar': ['foo', '1'], 'bar': False},
),
(['foo', '{{cookiecutter.project}}', None], ['foo', 'foobar', None]),
],
)
def test_convert_to_str_complex_variables(self, raw_var, rendered_var):
"""Verify tree items correctly rendered."""
env = environment.StrictEnvironment()
context = {'project': 'foobar'}
result = prompt.render_variable(env, raw_var, context)
> assert result == rendered_var
E AssertionError: assert ['foo', '{{cookiecutter.project}}', None] == ['foo', 'foobar', None]
E
E At index 1 diff: '{{cookiecutter.project}}' != 'foobar'
E
E Full diff:
E [
E 'foo',
E - 'foobar',
E + '{{cookiecutter.project}}',
E None,
E ]
tests/test_prompt.py:71: AssertionError
input]
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fb925c0>
context = {'cookiecutter': {'full_name': 'Your Name'}}
@pytest.mark.parametrize(
'context',
[
{'cookiecutter': {'full_name': 'Your Name'}},
{'cookiecutter': {'full_name': 'Řekni či napiš své jméno'}},
],
ids=['ASCII default prompt/input', 'Unicode default prompt/input'],
)
def test_prompt_for_config(self, monkeypatch, context):
"""Verify `prompt_for_config` call `read_user_variable` on text request."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default, prompts, prefix: default,
)
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:92:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Your Name', cookiecutter_dict = {'full_name': 'Your Name'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
input]
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fdf2500>
context = {'cookiecutter': {'full_name': 'Řekni či napiš své jméno'}}
@pytest.mark.parametrize(
'context',
[
{'cookiecutter': {'full_name': 'Your Name'}},
{'cookiecutter': {'full_name': 'Řekni či napiš své jméno'}},
],
ids=['ASCII default prompt/input', 'Unicode default prompt/input'],
)
def test_prompt_for_config(self, monkeypatch, context):
"""Verify `prompt_for_config` call `read_user_variable` on text request."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default, prompts, prefix: default,
)
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:92:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Řekni či napiš své jméno'
cookiecutter_dict = {'full_name': 'Řekni či napiš své jméno'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
input]
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f86dbd0>
context = {'cookiecutter': {'__prompts__': {'check': 'Checking', 'full_name': 'Name please'}, 'check': ['yes', 'no'], 'full_name': 'Your Name', 'nothing': 'ok'}}
@pytest.mark.parametrize(
'context',
[
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'nothing': 'ok',
'__prompts__': {
'full_name': 'Name please',
'check': 'Checking',
},
}
},
],
ids=['ASCII default prompt/input'],
)
def test_prompt_for_config_with_human_prompts(self, monkeypatch, context):
"""Verify call `read_user_variable` on request when human-readable prompts."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default, prompts, prefix: default,
)
monkeypatch.setattr(
'cookiecutter.prompt.read_user_yes_no',
lambda var, default, prompts, prefix: default,
)
monkeypatch.setattr(
'cookiecutter.prompt.read_user_choice',
lambda var, default, prompts, prefix: default,
)
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:127:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Your Name'
cookiecutter_dict = {'__prompts__': {'check': 'Checking', 'full_name': 'Name please'}, 'check': ['yes', 'no'], 'full_name': 'Your Name', 'nothing': 'ok'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_prompt_for_config_with_human_choices[context0]
test_prompt.py::TestPrompt::test_prompt_for_config_with_human_choices[context0]
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6fb3c5e0>
context = {'cookiecutter': {'__prompts__': {'check': 'Checking'}, 'check': ['yes', 'no'], 'full_name': 'Your Name'}}
@pytest.mark.parametrize(
'context',
[
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'check': 'Checking',
},
}
},
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'full_name': 'Name please',
'check': {'__prompt__': 'Checking', 'yes': 'Yes', 'no': 'No'},
},
}
},
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'full_name': 'Name please',
'check': {'no': 'No'},
},
}
},
],
)
def test_prompt_for_config_with_human_choices(self, monkeypatch, context):
"""Test prompts when human-readable labels for user choices."""
runner = click.testing.CliRunner()
with runner.isolation(input="\n\n\n"):
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:168:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Your Name'
cookiecutter_dict = {'__prompts__': {'check': 'Checking'}, 'check': ['yes', 'no'], 'full_name': 'Your Name'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_prompt_for_config_with_human_choices[context1]
test_prompt.py::TestPrompt::test_prompt_for_config_with_human_choices[context1]
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f3225f0>
context = {'cookiecutter': {'__prompts__': {'check': {'__prompt__': 'Checking', 'no': 'No', 'yes': 'Yes'}, 'full_name': 'Name please'}, 'check': ['yes', 'no'], 'full_name': 'Your Name'}}
@pytest.mark.parametrize(
'context',
[
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'check': 'Checking',
},
}
},
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'full_name': 'Name please',
'check': {'__prompt__': 'Checking', 'yes': 'Yes', 'no': 'No'},
},
}
},
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'full_name': 'Name please',
'check': {'no': 'No'},
},
}
},
],
)
def test_prompt_for_config_with_human_choices(self, monkeypatch, context):
"""Test prompts when human-readable labels for user choices."""
runner = click.testing.CliRunner()
with runner.isolation(input="\n\n\n"):
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:168:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Your Name'
cookiecutter_dict = {'__prompts__': {'check': {'__prompt__': 'Checking', 'no': 'No', 'yes': 'Yes'}, 'full_name': 'Name please'}, 'check': ['yes', 'no'], 'full_name': 'Your Name'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_prompt_for_config_with_human_choices[context2]
test_prompt.py::TestPrompt::test_prompt_for_config_with_human_choices[context2]
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f3ed750>
context = {'cookiecutter': {'__prompts__': {'check': {'no': 'No'}, 'full_name': 'Name please'}, 'check': ['yes', 'no'], 'full_name': 'Your Name'}}
@pytest.mark.parametrize(
'context',
[
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'check': 'Checking',
},
}
},
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'full_name': 'Name please',
'check': {'__prompt__': 'Checking', 'yes': 'Yes', 'no': 'No'},
},
}
},
{
'cookiecutter': {
'full_name': 'Your Name',
'check': ['yes', 'no'],
'__prompts__': {
'full_name': 'Name please',
'check': {'no': 'No'},
},
}
},
],
)
def test_prompt_for_config_with_human_choices(self, monkeypatch, context):
"""Test prompts when human-readable labels for user choices."""
runner = click.testing.CliRunner()
with runner.isolation(input="\n\n\n"):
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:168:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Your Name'
cookiecutter_dict = {'__prompts__': {'check': {'no': 'No'}, 'full_name': 'Name please'}, 'check': ['yes', 'no'], 'full_name': 'Your Name'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_prompt_for_config_dict
test_prompt.py::TestPrompt::test_prompt_for_config_dict
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f7319c0>
def test_prompt_for_config_dict(self, monkeypatch):
"""Verify `prompt_for_config` call `read_user_variable` on dict request."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_dict',
lambda var, default, prompts, prefix: {"key": "value", "integer": 37},
)
context = {'cookiecutter': {'details': {}}}
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:180:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
context = {'cookiecutter': {'details': {}}}, no_input = False
def prompt_for_config(context, no_input=False):
"""Prompt user to enter a new config.
:param dict context: Source for field names and sample values.
:param no_input: Do not prompt for user input and use only values from context.
:returns: A new config dict with user's responses
"""
cookiecutter_dict = context['cookiecutter']
env = create_env_with_context(context)
prompts = _prompts_from_options(cookiecutter_dict)
for key, raw in cookiecutter_dict.items():
if key.startswith('_'):
cookiecutter_dict[key] = raw
continue
try:
if isinstance(raw, list):
# Choice field
val = prompt_choice_for_config(
cookiecutter_dict, env, key, raw,
no_input, prompts
)
elif isinstance(raw, bool):
# Boolean field
val = read_user_yes_no(
key, raw,
prompts=prompts
) if not no_input else raw
elif isinstance(raw, dict):
# Dict field
> val = read_user_dict(
key, raw,
prompts=prompts
) if not no_input else raw
E TypeError: TestPrompt.test_prompt_for_config_dict..() missing 1 required positional argument: 'prefix'
cookiecutter/prompt.py:252: TypeError
test_prompt.py::TestPrompt::test_should_render_dict
test_prompt.py::TestPrompt::test_should_render_dict
self =
def test_should_render_dict(self):
"""Verify template inside dictionary variable rendered."""
context = {
'cookiecutter': {
'project_name': 'Slartibartfast',
'details': {
'{{cookiecutter.project_name}}': '{{cookiecutter.project_name}}'
},
}
}
> cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:194:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Slartibartfast'
cookiecutter_dict = {'details': {'{{cookiecutter.project_name}}': '{{cookiecutter.project_name}}'}, 'project_name': 'Slartibartfast'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_should_render_deep_dict
test_prompt.py::TestPrompt::test_should_render_deep_dict
self =
def test_should_render_deep_dict(self):
"""Verify nested structures like dict in dict, rendered correctly."""
context = {
'cookiecutter': {
'project_name': "Slartibartfast",
'details': {
"key": "value",
"integer_key": 37,
"other_name": '{{cookiecutter.project_name}}',
"dict_key": {
"deep_key": "deep_value",
"deep_integer": 42,
"deep_other_name": '{{cookiecutter.project_name}}',
"deep_list": [
"deep value 1",
"{{cookiecutter.project_name}}",
"deep value 3",
],
},
"list_key": [
"value 1",
"{{cookiecutter.project_name}}",
"value 3",
],
},
}
}
> cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:228:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Slartibartfast'
cookiecutter_dict = {'details': {'dict_key': {'deep_integer': 42, 'deep_key': 'deep_value', 'deep_list': ['deep value 1', '{{cookiecutter.project_name}}', 'deep value 3'], 'deep_other_name': '{{cookiecutter.project_name}}'}, 'integer_key': 37, 'key': 'value', 'list_key': ['value 1', '{{cookiecutter.project_name}}', 'value 3'], ...}, 'project_name': 'Slartibartfast'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_should_render_deep_dict_with_human_prompts
test_prompt.py::TestPrompt::test_should_render_deep_dict_with_human_prompts
self =
def test_should_render_deep_dict_with_human_prompts(self):
"""Verify dict rendered correctly when human-readable prompts."""
context = {
'cookiecutter': {
'project_name': "Slartibartfast",
'details': {
"key": "value",
"integer_key": 37,
"other_name": '{{cookiecutter.project_name}}',
"dict_key": {
"deep_key": "deep_value",
},
},
'__prompts__': {'project_name': 'Project name'},
}
}
> cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:261:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Slartibartfast'
cookiecutter_dict = {'__prompts__': {'project_name': 'Project name'}, 'details': {'dict_key': {'deep_key': 'deep_value'}, 'integer_key': 37, 'key': 'value', 'other_name': '{{cookiecutter.project_name}}'}, 'project_name': 'Slartibartfast'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_internal_use_no_human_prompts
test_prompt.py::TestPrompt::test_internal_use_no_human_prompts
self =
def test_internal_use_no_human_prompts(self):
"""Verify dict rendered correctly when human-readable prompts empty."""
context = {
'cookiecutter': {
'project_name': "Slartibartfast",
'__prompts__': {},
}
}
> cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:282:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Slartibartfast'
cookiecutter_dict = {'__prompts__': {}, 'project_name': 'Slartibartfast'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_prompt_for_templated_config
test_prompt.py::TestPrompt::test_prompt_for_templated_config
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f6a5180>
def test_prompt_for_templated_config(self, monkeypatch):
"""Verify Jinja2 templating works in unicode prompts."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default, prompts, prefix: default,
)
context = {
'cookiecutter': OrderedDict(
[
('project_name', 'A New Project'),
(
'pkg_name',
'{{ cookiecutter.project_name|lower|replace(" ", "") }}',
),
]
)
}
exp_cookiecutter_dict = {
'project_name': 'A New Project',
'pkg_name': 'anewproject',
}
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:309:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'A New Project'
cookiecutter_dict = OrderedDict([('project_name', 'A New Project'), ('pkg_name', '{{ cookiecutter.project_name|lower|replace(" ", "") }}')])
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_dont_prompt_for_private_context_var
test_prompt.py::TestPrompt::test_dont_prompt_for_private_context_var
self =
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f6a6f9b3a60>
def test_dont_prompt_for_private_context_var(self, monkeypatch):
"""Verify `read_user_variable` not called for private context variables."""
monkeypatch.setattr(
'cookiecutter.prompt.read_user_variable',
lambda var, default: pytest.fail(
'Should not try to read a response for private context var'
),
)
context = {'cookiecutter': {'_copy_without_render': ['*.html']}}
cookiecutter_dict = prompt.prompt_for_config(context)
> assert cookiecutter_dict == {'_copy_without_render': ['*.html']}
E AssertionError: assert {'cookiecutter': {'_copy_without_render': ['*.html']}} == {'_copy_without_render': ['*.html']}
E
E Left contains 1 more item:
E {'cookiecutter': {'_copy_without_render': ['*.html']}}
E Right contains 1 more item:
E {'_copy_without_render': ['*.html']}
E
E Full diff:
E {
E + 'cookiecutter': {
E - '_copy_without_render': [
E + '_copy_without_render': [
E ? ++++
E - '*.html',
E + '*.html',
E ? ++++
E + ],
E - ],
E ? ^
E + },
E ? ^
E }
tests/test_prompt.py:322: AssertionError
test_prompt.py::TestPrompt::test_should_render_private_variables_with_two_underscores
test_prompt.py::TestPrompt::test_should_render_private_variables_with_two_underscores
self =
def test_should_render_private_variables_with_two_underscores(self):
"""Test rendering of private variables with two underscores.
There are three cases:
1. Variables beginning with a single underscore are private and not rendered.
2. Variables beginning with a double underscore are private and are rendered.
3. Variables beginning with anything other than underscores are not private and
are rendered.
"""
context = {
'cookiecutter': OrderedDict(
[
('foo', 'Hello world'),
('bar', 123),
('rendered_foo', '{{ cookiecutter.foo|lower }}'),
('rendered_bar', 123),
('_hidden_foo', '{{ cookiecutter.foo|lower }}'),
('_hidden_bar', 123),
('__rendered_hidden_foo', '{{ cookiecutter.foo|lower }}'),
('__rendered_hidden_bar', 123),
]
)
}
> cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:347:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Hello world'
cookiecutter_dict = OrderedDict([('foo', 'Hello world'), ('bar', 123), ('rendered_foo', '{{ cookiecutter.foo|lower }}'), ('rendered_bar', 123), ('_hidden_foo', '{{ cookiecutter.foo|lower }}'), ('_hidden_bar', 123), ('__rendered_hidden_foo', '{{ cookiecutter.foo|lower }}'), ('__rendered_hidden_bar', 123)])
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPrompt::test_should_not_render_private_variables
test_prompt.py::TestPrompt::test_should_not_render_private_variables
self =
def test_should_not_render_private_variables(self):
"""Verify private(underscored) variables not rendered by `prompt_for_config`.
Private variables designed to be raw, same as context input.
"""
context = {
'cookiecutter': {
'project_name': 'Skip render',
'_skip_jinja_template': '{{cookiecutter.project_name}}',
'_skip_float': 123.25,
'_skip_integer': 123,
'_skip_boolean': True,
'_skip_nested': True,
}
}
> cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:376:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Skip render'
cookiecutter_dict = {'_skip_boolean': True, '_skip_float': 123.25, '_skip_integer': 123, '_skip_jinja_template': '{{cookiecutter.project_name}}', ...}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestReadUserChoice::test_should_invoke_read_user_choice
test_prompt.py::TestReadUserChoice::test_should_invoke_read_user_choice
self =
mocker =
def test_should_invoke_read_user_choice(self, mocker):
"""Verify correct function called for select(list) variables."""
prompt_choice = mocker.patch(
'cookiecutter.prompt.prompt_choice_for_config',
wraps=prompt.prompt_choice_for_config,
)
read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
read_user_choice.return_value = 'all'
read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
choices = ['landscape', 'portrait', 'all']
context = {'cookiecutter': {'orientation': choices}}
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:401:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:240: in prompt_for_config
val = prompt_choice_for_config(
/usr/lib/python3.10/unittest/mock.py:1114: in __call__
return self._mock_call(*args, **kwargs)
/usr/lib/python3.10/unittest/mock.py:1118: in _mock_call
return self._execute_mock_call(*args, **kwargs)
/usr/lib/python3.10/unittest/mock.py:1188: in _execute_mock_call
return self._mock_wraps(*args, **kwargs)
cookiecutter/prompt.py:218: in prompt_choice_for_config
rendered_options = [render_variable(env, opt, cookiecutter_dict) for opt in options]
cookiecutter/prompt.py:218: in
rendered_options = [render_variable(env, opt, cookiecutter_dict) for opt in options]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'landscape'
cookiecutter_dict = {'orientation': ['landscape', 'portrait', 'all']}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestReadUserChoice::test_should_invoke_read_user_variable
test_prompt.py::TestReadUserChoice::test_should_invoke_read_user_variable
self =
mocker =
def test_should_invoke_read_user_variable(self, mocker):
"""Verify correct function called for string input variables."""
read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
read_user_variable.return_value = 'Audrey Roy'
prompt_choice = mocker.patch('cookiecutter.prompt.prompt_choice_for_config')
read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
context = {'cookiecutter': {'full_name': 'Your Name'}}
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:421:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'Your Name', cookiecutter_dict = {'full_name': 'Your Name'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestReadUserChoice::test_should_render_choices
test_prompt.py::TestReadUserChoice::test_should_render_choices
self =
mocker =
def test_should_render_choices(self, mocker):
"""Verify Jinja2 templating engine works inside choices variables."""
read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
read_user_choice.return_value = 'anewproject'
read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
read_user_variable.return_value = 'A New Project'
rendered_choices = ['foo', 'anewproject', 'bar']
context = {
'cookiecutter': OrderedDict(
[
('project_name', 'A New Project'),
(
'pkg_name',
[
'foo',
'{{ cookiecutter.project_name|lower|replace(" ", "") }}',
'bar',
],
),
]
)
}
expected = {
'project_name': 'A New Project',
'pkg_name': 'anewproject',
}
> cookiecutter_dict = prompt.prompt_for_config(context)
tests/test_prompt.py:460:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = 'A New Project'
cookiecutter_dict = OrderedDict([('project_name', 'A New Project'), ('pkg_name', ['foo', '{{ cookiecutter.project_name|lower|replace(" ", "") }}', 'bar'])])
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::TestPromptChoiceForConfig::test_should_return_first_option_if_no_input
self =
mocker =
choices = ['landscape', 'portrait', 'all']
context = {'cookiecutter': {'orientation': ['landscape', 'portrait', 'all']}}
def test_should_return_first_option_if_no_input(self, mocker, choices, context):
"""Verify prompt_choice_for_config return first list option on no_input=True."""
read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
expected_choice = choices[0]
actual_choice = prompt.prompt_choice_for_config(
cookiecutter_dict=context,
env=environment.StrictEnvironment(),
key='orientation',
options=choices,
no_input=True, # Suppress user input
)
> assert not read_user_choice.called
E AssertionError: assert not True
E + where True = .called
tests/test_prompt.py:498: AssertionError
test_prompt.py::TestPromptChoiceForConfig::test_should_read_user_choice
test_prompt.py::TestPromptChoiceForConfig::test_should_read_user_choice
self =
args = ('orientation', ['landscape', 'portrait', 'all'], None, ''), kwargs = {}
expected = call('orientation', ['landscape', 'portrait', 'all'], None, '')
actual = call('orientation', ['landscape', 'portrait', 'all'], prompts=None, prefix='')
_error_message = ._error_message at 0x7f6a6eef5360>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: read_user_choice('orientation', ['landscape', 'portrait', 'all'], None, '')
E Actual: read_user_choice('orientation', ['landscape', 'portrait', 'all'], prompts=None, prefix='')
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('orientation', ['landscape', 'portrait', 'all'], None, ''), kwargs = {}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: read_user_choice('orientation', ['landscape', 'portrait', 'all'], None, '')
E Actual: read_user_choice('orientation', ['landscape', 'portrait', 'all'], prompts=None, prefix='')
E
E pytest introspection follows:
E
E Args:
E assert ('orientation', ['landscape', 'portrait', 'all']) == ('orientation', ['landscape', 'portrait', 'all'], None, '')
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'orientation',
E [
E 'landscape',
E 'portrait',
E 'all',
E ],
E - None,
E - '',
E )
E Kwargs:
E assert {'prompts': None, 'prefix': ''} == {}
E
E Left contains 2 more items:
E {'prefix': '', 'prompts': None}
E
E Full diff:
E - {}
E + {
E + 'prefix': '',
E + 'prompts': None,
E + }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
self =
mocker =
choices = ['landscape', 'portrait', 'all']
context = {'cookiecutter': {'orientation': ['landscape', 'portrait', 'all']}}
def test_should_read_user_choice(self, mocker, choices, context):
"""Verify prompt_choice_for_config return user selection on no_input=False."""
read_user_choice = mocker.patch('cookiecutter.prompt.read_user_choice')
read_user_choice.return_value = 'all'
expected_choice = 'all'
actual_choice = prompt.prompt_choice_for_config(
cookiecutter_dict=context,
env=environment.StrictEnvironment(),
key='orientation',
options=choices,
no_input=False, # Ask the user for input
)
> read_user_choice.assert_called_once_with('orientation', choices, None, '')
E AssertionError: expected call not found.
E Expected: read_user_choice('orientation', ['landscape', 'portrait', 'all'], None, '')
E Actual: read_user_choice('orientation', ['landscape', 'portrait', 'all'], prompts=None, prefix='')
E
E pytest introspection follows:
E
E Args:
E assert ('orientation', ['landscape', 'portrait', 'all']) == ('orientation', ['landscape', 'portrait', 'all'], None, '')
E
E Right contains 2 more items, first extra item: None
E
E Full diff:
E (
E 'orientation',
E [
E 'landscape',
E 'portrait',
E 'all',
E ],
E - None,
E - '',
E )
E Kwargs:
E assert {'prompts': None, 'prefix': ''} == {}
E
E Left contains 2 more items:
E {'prefix': '', 'prompts': None}
E
E Full diff:
E - {}
E + {
E + 'prefix': '',
E + 'prompts': None,
E + }
tests/test_prompt.py:515: AssertionError
test_prompt.py::TestReadUserYesNo::test_should_invoke_read_user_yes_no[True]
test_prompt.py::TestReadUserYesNo::test_should_invoke_read_user_yes_no[True]
self =
args = ('run_as_docker', True, {}, ' [dim][1/1][/] '), kwargs = {}
expected = call('run_as_docker', True, {}, ' [dim][1/1][/] ')
actual = call('run_as_docker', True, prompts={})
_error_message = ._error_message at 0x7f6a6f1af640>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: read_user_yes_no('run_as_docker', True, {}, ' [dim][1/1][/] ')
E Actual: read_user_yes_no('run_as_docker', True, prompts={})
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('run_as_docker', True, {}, ' [dim][1/1][/] '), kwargs = {}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: read_user_yes_no('run_as_docker', True, {}, ' [dim][1/1][/] ')
E Actual: read_user_yes_no('run_as_docker', True, prompts={})
E
E pytest introspection follows:
E
E Args:
E assert ('run_as_docker', True) == ('run_as_docker', True, {}, ' [dim][1/1][/] ')
E
E Right contains 2 more items, first extra item: {}
E
E Full diff:
E (
E 'run_as_docker',
E True,
E - {},
E - ' [dim][1/1][/] ',
E )
E Kwargs:
E assert {'prompts': {}} == {}
E
E Left contains 1 more item:
E {'prompts': {}}
E
E Full diff:
E - {}
E + {
E + 'prompts': {},
E + }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
self =
mocker =
run_as_docker = True
@pytest.mark.parametrize(
'run_as_docker',
(
True,
False,
),
)
def test_should_invoke_read_user_yes_no(self, mocker, run_as_docker):
"""Verify correct function called for boolean variables."""
read_user_yes_no = mocker.patch('cookiecutter.prompt.read_user_yes_no')
read_user_yes_no.return_value = run_as_docker
read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
context = {'cookiecutter': {'run_as_docker': run_as_docker}}
cookiecutter_dict = prompt.prompt_for_config(context)
assert not read_user_variable.called
> read_user_yes_no.assert_called_once_with(
'run_as_docker', run_as_docker, {}, DEFAULT_PREFIX
)
E AssertionError: expected call not found.
E Expected: read_user_yes_no('run_as_docker', True, {}, ' [dim][1/1][/] ')
E Actual: read_user_yes_no('run_as_docker', True, prompts={})
E
E pytest introspection follows:
E
E Args:
E assert ('run_as_docker', True) == ('run_as_docker', True, {}, ' [dim][1/1][/] ')
E
E Right contains 2 more items, first extra item: {}
E
E Full diff:
E (
E 'run_as_docker',
E True,
E - {},
E - ' [dim][1/1][/] ',
E )
E Kwargs:
E assert {'prompts': {}} == {}
E
E Left contains 1 more item:
E {'prompts': {}}
E
E Full diff:
E - {}
E + {
E + 'prompts': {},
E + }
tests/test_prompt.py:541: AssertionError
test_prompt.py::TestReadUserYesNo::test_should_invoke_read_user_yes_no[False]
test_prompt.py::TestReadUserYesNo::test_should_invoke_read_user_yes_no[False]
self =
args = ('run_as_docker', False, {}, ' [dim][1/1][/] '), kwargs = {}
expected = call('run_as_docker', False, {}, ' [dim][1/1][/] ')
actual = call('run_as_docker', False, prompts={})
_error_message = ._error_message at 0x7f6a6eef51b0>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: read_user_yes_no('run_as_docker', False, {}, ' [dim][1/1][/] ')
E Actual: read_user_yes_no('run_as_docker', False, prompts={})
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = ('run_as_docker', False, {}, ' [dim][1/1][/] '), kwargs = {}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: read_user_yes_no('run_as_docker', False, {}, ' [dim][1/1][/] ')
E Actual: read_user_yes_no('run_as_docker', False, prompts={})
E
E pytest introspection follows:
E
E Args:
E assert ('run_as_docker', False) == ('run_as_docker', False, {}, ' [dim][1/1][/] ')
E
E Right contains 2 more items, first extra item: {}
E
E Full diff:
E (
E 'run_as_docker',
E False,
E - {},
E - ' [dim][1/1][/] ',
E )
E Kwargs:
E assert {'prompts': {}} == {}
E
E Left contains 1 more item:
E {'prompts': {}}
E
E Full diff:
E - {}
E + {
E + 'prompts': {},
E + }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
self =
mocker =
run_as_docker = False
@pytest.mark.parametrize(
'run_as_docker',
(
True,
False,
),
)
def test_should_invoke_read_user_yes_no(self, mocker, run_as_docker):
"""Verify correct function called for boolean variables."""
read_user_yes_no = mocker.patch('cookiecutter.prompt.read_user_yes_no')
read_user_yes_no.return_value = run_as_docker
read_user_variable = mocker.patch('cookiecutter.prompt.read_user_variable')
context = {'cookiecutter': {'run_as_docker': run_as_docker}}
cookiecutter_dict = prompt.prompt_for_config(context)
assert not read_user_variable.called
> read_user_yes_no.assert_called_once_with(
'run_as_docker', run_as_docker, {}, DEFAULT_PREFIX
)
E AssertionError: expected call not found.
E Expected: read_user_yes_no('run_as_docker', False, {}, ' [dim][1/1][/] ')
E Actual: read_user_yes_no('run_as_docker', False, prompts={})
E
E pytest introspection follows:
E
E Args:
E assert ('run_as_docker', False) == ('run_as_docker', False, {}, ' [dim][1/1][/] ')
E
E Right contains 2 more items, first extra item: {}
E
E Full diff:
E (
E 'run_as_docker',
E False,
E - {},
E - ' [dim][1/1][/] ',
E )
E Kwargs:
E assert {'prompts': {}} == {}
E
E Left contains 1 more item:
E {'prompts': {}}
E
E Full diff:
E - {}
E + {
E + 'prompts': {},
E + }
tests/test_prompt.py:541: AssertionError
test_prompt.py::TestReadUserYesNo::test_boolean_parameter_no_input
self =
def test_boolean_parameter_no_input(self):
"""Verify boolean parameter sent to prompt for config with no input."""
context = {
'cookiecutter': {
'run_as_docker': True,
}
}
cookiecutter_dict = prompt.prompt_for_config(context, no_input=True)
> assert cookiecutter_dict == context['cookiecutter']
E AssertionError: assert {'cookiecutter': {'run_as_docker': True}} == {'run_as_docker': True}
E
E Left contains 1 more item:
E {'cookiecutter': {'run_as_docker': True}}
E Right contains 1 more item:
E {'run_as_docker': True}
E
E Full diff:
E {
E + 'cookiecutter': {
E - 'run_as_docker': True,
E + 'run_as_docker': True,
E ? ++++
E + },
E }
tests/test_prompt.py:554: AssertionError
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict]
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict]
context = {'cookiecutter': {'foo': '{{cookiecutter.nope}}'}}
@pytest.mark.parametrize(
'context',
(
{'cookiecutter': {'foo': '{{cookiecutter.nope}}'}},
{'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}},
{'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}},
{'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}},
),
ids=[
'Undefined variable in cookiecutter dict',
'Undefined variable in cookiecutter dict with choices',
'Undefined variable in cookiecutter dict with dict_key',
'Undefined variable in cookiecutter dict with key_value',
],
)
def test_undefined_variable(context):
"""Verify `prompt.prompt_for_config` raises correct error."""
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:575:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:258: in prompt_for_config
val = render_variable(env, raw, cookiecutter_dict)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = '{{cookiecutter.nope}}'
cookiecutter_dict = {'foo': '{{cookiecutter.nope}}'}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict with choices]
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict with choices]
context = {'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}}
@pytest.mark.parametrize(
'context',
(
{'cookiecutter': {'foo': '{{cookiecutter.nope}}'}},
{'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}},
{'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}},
{'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}},
),
ids=[
'Undefined variable in cookiecutter dict',
'Undefined variable in cookiecutter dict with choices',
'Undefined variable in cookiecutter dict with dict_key',
'Undefined variable in cookiecutter dict with key_value',
],
)
def test_undefined_variable(context):
"""Verify `prompt.prompt_for_config` raises correct error."""
with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
> prompt.prompt_for_config(context, no_input=True)
tests/test_prompt.py:575:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:240: in prompt_for_config
val = prompt_choice_for_config(
cookiecutter/prompt.py:218: in prompt_choice_for_config
rendered_options = [render_variable(env, opt, cookiecutter_dict) for opt in options]
cookiecutter/prompt.py:218: in
rendered_options = [render_variable(env, opt, cookiecutter_dict) for opt in options]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
env = None, raw = '123'
cookiecutter_dict = {'foo': ['123', '{{cookiecutter.nope}}', '456']}
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
Inside the prompting taken from the cookiecutter.json file, this renders
the next variable. For example, if a project_name is "Peanut Butter
Cookie", the repo_name could be be rendered with:
`{{ cookiecutter.project_name.replace(" ", "_") }}`.
This is then presented to the user as the default.
:param Environment env: A Jinja2 Environment object.
:param raw: The next value to be prompted for by the user.
:param dict cookiecutter_dict: The current context as it's gradually
being populated with variables.
:return: The rendered value for the default variable.
"""
if not isinstance(raw, str):
return raw
> template = env.from_string(raw)
E AttributeError: 'NoneType' object has no attribute 'from_string'
cookiecutter/prompt.py:161: AttributeError
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict with dict_key]
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict with dict_key]
context = {'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}}
@pytest.mark.parametrize(
'context',
(
{'cookiecutter': {'foo': '{{cookiecutter.nope}}'}},
{'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}},
{'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}},
{'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}},
),
ids=[
'Undefined variable in cookiecutter dict',
'Undefined variable in cookiecutter dict with choices',
'Undefined variable in cookiecutter dict with dict_key',
'Undefined variable in cookiecutter dict with key_value',
],
)
def test_undefined_variable(context):
"""Verify `prompt.prompt_for_config` raises correct error."""
> with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
E Failed: DID NOT RAISE
tests/test_prompt.py:574: Failed
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict with key_value]
test_prompt.py::test_undefined_variable[Undefined variable in cookiecutter dict with key_value]
context = {'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}}
@pytest.mark.parametrize(
'context',
(
{'cookiecutter': {'foo': '{{cookiecutter.nope}}'}},
{'cookiecutter': {'foo': ['123', '{{cookiecutter.nope}}', '456']}},
{'cookiecutter': {'foo': {'{{cookiecutter.nope}}': 'value'}}},
{'cookiecutter': {'foo': {'key': '{{cookiecutter.nope}}'}}},
),
ids=[
'Undefined variable in cookiecutter dict',
'Undefined variable in cookiecutter dict with choices',
'Undefined variable in cookiecutter dict with dict_key',
'Undefined variable in cookiecutter dict with key_value',
],
)
def test_undefined_variable(context):
"""Verify `prompt.prompt_for_config` raises correct error."""
> with pytest.raises(exceptions.UndefinedVariableInTemplate) as err:
E Failed: DID NOT RAISE
tests/test_prompt.py:574: Failed
test_prompt.py::test_cookiecutter_nested_templates[fake-nested-templates-fake-project]
test_prompt.py::test_cookiecutter_nested_templates[fake-nested-templates-fake-project]
template_dir = 'fake-nested-templates'
expected = PosixPath('/testbed/tests/fake-nested-templates/fake-project')
@pytest.mark.parametrize(
"template_dir,expected",
[
["fake-nested-templates", "fake-project"],
["fake-nested-templates-old-style", "fake-package"],
],
)
def test_cookiecutter_nested_templates(template_dir: str, expected: str):
"""Test nested_templates generation."""
from cookiecutter import prompt
main_dir = (Path("tests") / template_dir).resolve()
cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
context = {"cookiecutter": cookiecuter_context}
output_dir = prompt.choose_nested_template(context, main_dir, no_input=True)
expected = (Path(main_dir) / expected).resolve()
> assert output_dir == f"{expected}"
E AssertionError: assert {'cookiecutter': {'templates': {'fake-package': {'description': 'A cookiecutter template for a package', 'path': './fake-package', 'title': 'A Fake Package'}, 'fake-project': {'description': 'A cookiecutter template for a project', 'path': './fake-project', 'title': 'A Fake Project'}}}} == '/testbed/tests/fake-nested-templates/fake-project'
tests/test_prompt.py:598: AssertionError
test_prompt.py::test_cookiecutter_nested_templates[fake-nested-templates-old-style-fake-package]
test_prompt.py::test_cookiecutter_nested_templates[fake-nested-templates-old-style-fake-package]
template_dir = 'fake-nested-templates-old-style'
expected = PosixPath('/testbed/tests/fake-nested-templates-old-style/fake-package')
@pytest.mark.parametrize(
"template_dir,expected",
[
["fake-nested-templates", "fake-project"],
["fake-nested-templates-old-style", "fake-package"],
],
)
def test_cookiecutter_nested_templates(template_dir: str, expected: str):
"""Test nested_templates generation."""
from cookiecutter import prompt
main_dir = (Path("tests") / template_dir).resolve()
cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
context = {"cookiecutter": cookiecuter_context}
output_dir = prompt.choose_nested_template(context, main_dir, no_input=True)
expected = (Path(main_dir) / expected).resolve()
> assert output_dir == f"{expected}"
E AssertionError: assert {'cookiecutter': {'__prompts__': {'template': {'__prompt__': 'Select a template', 'fake-package (./fake-package)': 'Fake Package'}}, 'template': ['fake-package (./fake-package)']}} == '/testbed/tests/fake-nested-templates-old-style/fake-package'
tests/test_prompt.py:598: AssertionError
test_prompt.py::test_cookiecutter_nested_templates_invalid_paths[]
test_prompt.py::test_cookiecutter_nested_templates_invalid_paths[]
path = ''
@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux / macos test")
@pytest.mark.parametrize(
"path",
[
"",
"/tmp",
"/foo",
],
)
def test_cookiecutter_nested_templates_invalid_paths(path: str):
"""Test nested_templates generation."""
from cookiecutter import prompt
main_dir = (Path("tests") / "fake-nested-templates").resolve()
cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
cookiecuter_context["templates"]["fake-project"]["path"] = path
context = {"cookiecutter": cookiecuter_context}
> with pytest.raises(ValueError) as exc:
E Failed: DID NOT RAISE
tests/test_prompt.py:618: Failed
tmp]
tmp]
path = '/tmp'
@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux / macos test")
@pytest.mark.parametrize(
"path",
[
"",
"/tmp",
"/foo",
],
)
def test_cookiecutter_nested_templates_invalid_paths(path: str):
"""Test nested_templates generation."""
from cookiecutter import prompt
main_dir = (Path("tests") / "fake-nested-templates").resolve()
cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
cookiecuter_context["templates"]["fake-project"]["path"] = path
context = {"cookiecutter": cookiecuter_context}
> with pytest.raises(ValueError) as exc:
E Failed: DID NOT RAISE
tests/test_prompt.py:618: Failed
foo]
foo]
path = '/foo'
@pytest.mark.skipif(sys.platform.startswith('win'), reason="Linux / macos test")
@pytest.mark.parametrize(
"path",
[
"",
"/tmp",
"/foo",
],
)
def test_cookiecutter_nested_templates_invalid_paths(path: str):
"""Test nested_templates generation."""
from cookiecutter import prompt
main_dir = (Path("tests") / "fake-nested-templates").resolve()
cookiecuter_context = json.loads((main_dir / "cookiecutter.json").read_text())
cookiecuter_context["templates"]["fake-project"]["path"] = path
context = {"cookiecutter": cookiecuter_context}
> with pytest.raises(ValueError) as exc:
E Failed: DID NOT RAISE
tests/test_prompt.py:618: Failed
test_prompt.py::test_prompt_should_ask_and_rm_repo_dir
test_prompt.py::test_prompt_should_ask_and_rm_repo_dir
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_ask_and_rm_0')
def test_prompt_should_ask_and_rm_repo_dir(mocker, tmp_path):
"""In `prompt_and_delete()`, if the user agrees to delete/reclone the \
repo, the repo should be deleted."""
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no', return_value=True
)
repo_dir = Path(tmp_path, 'repo')
repo_dir.mkdir()
> deleted = prompt.prompt_and_delete(str(repo_dir))
tests/test_prompt.py:654:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:309: in prompt_and_delete
ok_to_delete = YesNoPrompt.ask(
.venv/lib/python3.10/site-packages/rich/prompt.py:149: in ask
return _prompt(default=default, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:292: in __call__
value = self.get_input(self.console, prompt, self.password, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:211: in get_input
return console.input(prompt, password=password, stream=stream)
.venv/lib/python3.10/site-packages/rich/console.py:2156: in input
result = input()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x7f6a71589180>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
.venv/lib/python3.10/site-packages/_pytest/capture.py:209: OSError
test_prompt.py::test_prompt_should_ask_and_exit_on_user_no_answer
test_prompt.py::test_prompt_should_ask_and_exit_on_user_no_answer
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_ask_and_exi0')
def test_prompt_should_ask_and_exit_on_user_no_answer(mocker, tmp_path):
"""In `prompt_and_delete()`, if the user decline to delete/reclone the \
repo, cookiecutter should exit."""
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no',
return_value=False,
)
mock_sys_exit = mocker.patch('sys.exit', return_value=True)
repo_dir = Path(tmp_path, 'repo')
repo_dir.mkdir()
> deleted = prompt.prompt_and_delete(str(repo_dir))
tests/test_prompt.py:672:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:309: in prompt_and_delete
ok_to_delete = YesNoPrompt.ask(
.venv/lib/python3.10/site-packages/rich/prompt.py:149: in ask
return _prompt(default=default, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:292: in __call__
value = self.get_input(self.console, prompt, self.password, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:211: in get_input
return console.input(prompt, password=password, stream=stream)
.venv/lib/python3.10/site-packages/rich/console.py:2156: in input
result = input()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x7f6a71589180>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
.venv/lib/python3.10/site-packages/_pytest/capture.py:209: OSError
test_prompt.py::test_prompt_should_ask_and_rm_repo_file
test_prompt.py::test_prompt_should_ask_and_rm_repo_file
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_ask_and_rm_1')
def test_prompt_should_ask_and_rm_repo_file(mocker, tmp_path):
"""In `prompt_and_delete()`, if the user agrees to delete/reclone a \
repo file, the repo should be deleted."""
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
)
repo_file = tmp_path.joinpath('repo.zip')
repo_file.write_text('this is zipfile content')
> deleted = prompt.prompt_and_delete(str(repo_file))
tests/test_prompt.py:690:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:309: in prompt_and_delete
ok_to_delete = YesNoPrompt.ask(
.venv/lib/python3.10/site-packages/rich/prompt.py:149: in ask
return _prompt(default=default, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:292: in __call__
value = self.get_input(self.console, prompt, self.password, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:211: in get_input
return console.input(prompt, password=password, stream=stream)
.venv/lib/python3.10/site-packages/rich/console.py:2156: in input
result = input()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x7f6a71589180>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
.venv/lib/python3.10/site-packages/_pytest/capture.py:209: OSError
test_prompt.py::test_prompt_should_ask_and_keep_repo_on_no_reuse
test_prompt.py::test_prompt_should_ask_and_keep_repo_on_no_reuse
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_ask_and_kee0')
def test_prompt_should_ask_and_keep_repo_on_no_reuse(mocker, tmp_path):
"""In `prompt_and_delete()`, if the user wants to keep their old \
cloned template repo, it should not be deleted."""
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no', return_value=False, autospec=True
)
repo_dir = Path(tmp_path, 'repo')
repo_dir.mkdir()
with pytest.raises(SystemExit):
> prompt.prompt_and_delete(str(repo_dir))
tests/test_prompt.py:707:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:309: in prompt_and_delete
ok_to_delete = YesNoPrompt.ask(
.venv/lib/python3.10/site-packages/rich/prompt.py:149: in ask
return _prompt(default=default, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:292: in __call__
value = self.get_input(self.console, prompt, self.password, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:211: in get_input
return console.input(prompt, password=password, stream=stream)
.venv/lib/python3.10/site-packages/rich/console.py:2156: in input
result = input()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x7f6a71589180>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
.venv/lib/python3.10/site-packages/_pytest/capture.py:209: OSError
test_prompt.py::test_prompt_should_ask_and_keep_repo_on_reuse
test_prompt.py::test_prompt_should_ask_and_keep_repo_on_reuse
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_ask_and_kee1')
def test_prompt_should_ask_and_keep_repo_on_reuse(mocker, tmp_path):
"""In `prompt_and_delete()`, if the user wants to keep their old \
cloned template repo, it should not be deleted."""
def answer(question, default):
return 'okay to delete' not in question
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no', side_effect=answer, autospec=True
)
repo_dir = Path(tmp_path, 'repo')
repo_dir.mkdir()
> deleted = prompt.prompt_and_delete(str(repo_dir))
tests/test_prompt.py:726:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:309: in prompt_and_delete
ok_to_delete = YesNoPrompt.ask(
.venv/lib/python3.10/site-packages/rich/prompt.py:149: in ask
return _prompt(default=default, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:292: in __call__
value = self.get_input(self.console, prompt, self.password, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:211: in get_input
return console.input(prompt, password=password, stream=stream)
.venv/lib/python3.10/site-packages/rich/console.py:2156: in input
result = input()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x7f6a71589180>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
.venv/lib/python3.10/site-packages/_pytest/capture.py:209: OSError
test_prompt.py::test_prompt_should_not_ask_if_no_input_and_rm_repo_dir
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_not_ask_if_0')
def test_prompt_should_not_ask_if_no_input_and_rm_repo_dir(mocker, tmp_path):
"""Prompt should not ask if no input and rm dir.
In `prompt_and_delete()`, if `no_input` is True, the call to
`prompt.read_user_yes_no()` should be suppressed.
"""
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
)
repo_dir = Path(tmp_path, 'repo')
repo_dir.mkdir()
deleted = prompt.prompt_and_delete(str(repo_dir), no_input=True)
assert not mock_read_user.called
> assert not repo_dir.exists()
E AssertionError: assert not True
E + where True = exists()
E + where exists = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_not_ask_if_0/repo').exists
tests/test_prompt.py:748: AssertionError
test_prompt.py::test_prompt_should_not_ask_if_no_input_and_rm_repo_file
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_not_ask_if_1')
def test_prompt_should_not_ask_if_no_input_and_rm_repo_file(mocker, tmp_path):
"""Prompt should not ask if no input and rm file.
In `prompt_and_delete()`, if `no_input` is True, the call to
`prompt.read_user_yes_no()` should be suppressed.
"""
mock_read_user = mocker.patch(
'cookiecutter.prompt.read_user_yes_no', return_value=True, autospec=True
)
repo_file = tmp_path.joinpath('repo.zip')
repo_file.write_text('this is zipfile content')
deleted = prompt.prompt_and_delete(str(repo_file), no_input=True)
assert not mock_read_user.called
> assert not repo_file.exists()
E AssertionError: assert not True
E + where True = exists()
E + where exists = PosixPath('/tmp/pytest-of-root/pytest-0/test_prompt_should_not_ask_if_1/repo.zip').exists
tests/test_prompt.py:768: AssertionError
test_read_user_choice.py::test_click_invocation[1-hello]
test_read_user_choice.py::test_click_invocation[1-hello]
mocker =
user_choice = 1, expected_value = 'hello'
@pytest.mark.parametrize('user_choice, expected_value', enumerate(OPTIONS, 1))
def test_click_invocation(mocker, user_choice, expected_value):
"""Test click function called correctly by cookiecutter.
Test for choice type invocation.
"""
prompt = mocker.patch('rich.prompt.Prompt.ask')
prompt.return_value = f'{user_choice}'
> assert read_user_choice('varname', OPTIONS) == expected_value
E AssertionError: assert 'world' == 'hello'
E
E - hello
E + world
tests/test_read_user_choice.py:27: AssertionError
test_read_user_choice.py::test_click_invocation[2-world]
test_read_user_choice.py::test_click_invocation[2-world]
mocker =
user_choice = 2, expected_value = 'world'
@pytest.mark.parametrize('user_choice, expected_value', enumerate(OPTIONS, 1))
def test_click_invocation(mocker, user_choice, expected_value):
"""Test click function called correctly by cookiecutter.
Test for choice type invocation.
"""
prompt = mocker.patch('rich.prompt.Prompt.ask')
prompt.return_value = f'{user_choice}'
> assert read_user_choice('varname', OPTIONS) == expected_value
E AssertionError: assert 'foo' == 'world'
E
E - world
E + foo
tests/test_read_user_choice.py:27: AssertionError
test_read_user_choice.py::test_click_invocation[3-foo]
test_read_user_choice.py::test_click_invocation[3-foo]
mocker =
user_choice = 3, expected_value = 'foo'
@pytest.mark.parametrize('user_choice, expected_value', enumerate(OPTIONS, 1))
def test_click_invocation(mocker, user_choice, expected_value):
"""Test click function called correctly by cookiecutter.
Test for choice type invocation.
"""
prompt = mocker.patch('rich.prompt.Prompt.ask')
prompt.return_value = f'{user_choice}'
> assert read_user_choice('varname', OPTIONS) == expected_value
E AssertionError: assert 'bar' == 'foo'
E
E - foo
E + bar
tests/test_read_user_choice.py:27: AssertionError
test_read_user_choice.py::test_click_invocation[4-bar]
test_read_user_choice.py::test_click_invocation[4-bar]
mocker =
user_choice = 4, expected_value = 'bar'
@pytest.mark.parametrize('user_choice, expected_value', enumerate(OPTIONS, 1))
def test_click_invocation(mocker, user_choice, expected_value):
"""Test click function called correctly by cookiecutter.
Test for choice type invocation.
"""
prompt = mocker.patch('rich.prompt.Prompt.ask')
prompt.return_value = f'{user_choice}'
> assert read_user_choice('varname', OPTIONS) == expected_value
tests/test_read_user_choice.py:27:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
var_name = 'varname', options = ['hello', 'world', 'foo', 'bar'], prompts = {}
prefix = ''
def read_user_choice(var_name, options, prompts=None, prefix=''):
"""Prompt the user to choose from several options for the given variable.
The first item will be returned if no input happens.
:param str var_name: Variable as specified in the context
:param list options: Sequence of options that are available to select from
:param prompts: Optional dict with custom prompts for variables
:param prefix: Optional prefix to use for variable prompts
:return: Exactly one item of ``options`` that has been chosen by the user
"""
if not options:
raise ValueError('Options list must not be empty')
if prompts is None:
prompts = {}
prompt_text = prompts.get(var_name, f'{prefix}{var_name}')
choices = [str(i) for i in range(len(options))]
choice_map = dict(zip(choices, options))
choice_lines = [f'{i}) {opt}' for i, opt in enumerate(options)]
choice_text = '\n'.join(choice_lines)
prompt_text = f'{prompt_text}\n{choice_text}\nChoose from {min(choices)} to {max(choices)}'
choice = Prompt.ask(prompt_text, choices=choices, default='0')
> return choice_map[choice]
E KeyError: '4'
cookiecutter/prompt.py:96: KeyError
test_read_user_choice.py::test_raise_if_options_is_not_a_non_empty_list
test_read_user_choice.py::test_raise_if_options_is_not_a_non_empty_list
def test_raise_if_options_is_not_a_non_empty_list():
"""Test function called by cookiecutter raise expected errors.
Test for choice type invocation.
"""
with pytest.raises(TypeError):
> read_user_choice('foo', 'NOT A LIST')
tests/test_read_user_choice.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cookiecutter/prompt.py:95: in read_user_choice
choice = Prompt.ask(prompt_text, choices=choices, default='0')
.venv/lib/python3.10/site-packages/rich/prompt.py:149: in ask
return _prompt(default=default, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:292: in __call__
value = self.get_input(self.console, prompt, self.password, stream=stream)
.venv/lib/python3.10/site-packages/rich/prompt.py:211: in get_input
return console.input(prompt, password=password, stream=stream)
.venv/lib/python3.10/site-packages/rich/console.py:2156: in input
result = input()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.capture.DontReadFromInput object at 0x7f6a71589180>, size = -1
def read(self, size: int = -1) -> str:
> raise OSError(
"pytest: reading from stdin while output is captured! Consider using `-s`."
)
E OSError: pytest: reading from stdin while output is captured! Consider using `-s`.
.venv/lib/python3.10/site-packages/_pytest/capture.py:209: OSError
test_read_user_dict.py::test_process_json_invalid_json
test_read_user_dict.py::test_process_json_invalid_json
def test_process_json_invalid_json():
"""Test `process_json` for correct error on malformed input."""
> with pytest.raises(InvalidResponse) as exc_info:
E Failed: DID NOT RAISE
tests/test_read_user_dict.py:12: Failed
test_read_user_dict.py::test_process_json_non_dict
test_read_user_dict.py::test_process_json_non_dict
def test_process_json_non_dict():
"""Test `process_json` for correct error on non-JSON input."""
> with pytest.raises(InvalidResponse) as exc_info:
E Failed: DID NOT RAISE
tests/test_read_user_dict.py:20: Failed
test_read_user_dict.py::test_should_raise_type_error
test_read_user_dict.py::test_should_raise_type_error
mocker =
def test_should_raise_type_error(mocker):
"""Test `default_value` arg verification in `read_user_dict` function."""
prompt = mocker.patch('cookiecutter.prompt.JsonPrompt.ask')
> with pytest.raises(TypeError):
E Failed: DID NOT RAISE
tests/test_read_user_dict.py:79: Failed
test_read_user_dict.py::test_should_call_prompt_with_process_json
test_read_user_dict.py::test_should_call_prompt_with_process_json
mocker =
def test_should_call_prompt_with_process_json(mocker):
"""Test to make sure that `process_json` is actually being used.
Verifies generation of a processor for the user input.
"""
mock_prompt = mocker.patch('cookiecutter.prompt.JsonPrompt.ask', autospec=True)
read_user_dict('name', {'project_slug': 'pytest-plugin'})
print(mock_prompt.call_args)
args, kwargs = mock_prompt.call_args
> assert args == ('name [cyan bold](default)[/]',)
E AssertionError: assert ('name',) == ('name [cyan bold](default)[/]',)
E
E At index 0 diff: 'name' != 'name [cyan bold](default)[/]'
E
E Full diff:
E (
E - 'name [cyan bold](default)[/]',
E + 'name',
E )
tests/test_read_user_dict.py:95: AssertionError
test_read_user_dict.py::test_read_user_dict_default_value[\n]
test_read_user_dict.py::test_read_user_dict_default_value[\n]
mocker =
input = '\n'
@pytest.mark.parametrize("input", ["\n", "\ndefault\n"])
def test_read_user_dict_default_value(mocker, input):
"""Make sure that `read_user_dict` returns the default value.
Verify return of a dict variable rather than the display value.
"""
runner = click.testing.CliRunner()
with runner.isolation(input=input):
val = read_user_dict('name', {'project_slug': 'pytest-plugin'})
> assert val == {'project_slug': 'pytest-plugin'}
E assert '{"project_slug": "pytest-plugin"}' == {'project_slug': 'pytest-plugin'}
tests/test_read_user_dict.py:122: AssertionError
test_read_user_dict.py::test_read_user_dict_default_value[\ndefault\n]
test_read_user_dict.py::test_read_user_dict_default_value[\ndefault\n]
mocker =
input = '\ndefault\n'
@pytest.mark.parametrize("input", ["\n", "\ndefault\n"])
def test_read_user_dict_default_value(mocker, input):
"""Make sure that `read_user_dict` returns the default value.
Verify return of a dict variable rather than the display value.
"""
runner = click.testing.CliRunner()
with runner.isolation(input=input):
val = read_user_dict('name', {'project_slug': 'pytest-plugin'})
> assert val == {'project_slug': 'pytest-plugin'}
E assert '{"project_slug": "pytest-plugin"}' == {'project_slug': 'pytest-plugin'}
tests/test_read_user_dict.py:122: AssertionError
test_read_user_variable.py::test_input_loop_with_null_default_value
mock_prompt =
def test_input_loop_with_null_default_value(mock_prompt):
"""Test `Prompt.ask` is run repeatedly until a valid answer is provided.
Test for `default_value` parameter equal to None.
"""
# Simulate user providing None input initially and then a valid input
mock_prompt.side_effect = [None, DEFAULT]
> assert read_user_variable(VARIABLE, None) == DEFAULT
E AssertionError: assert None == 'Kivy Project'
E + where None = read_user_variable('project_name', None)
tests/test_read_user_variable.py:37: AssertionError
test_repo_not_found.py::test_should_raise_error_if_repo_does_not_exist
test_repo_not_found.py::test_should_raise_error_if_repo_does_not_exist
def test_should_raise_error_if_repo_does_not_exist():
"""Cookiecutter invocation with non-exist repository should raise error."""
with pytest.raises(exceptions.RepositoryNotFound):
> main.cookiecutter('definitely-not-a-valid-repo-dir')
tests/test_repo_not_found.py:11:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'definitely-not-a-valid-repo-dir', checkout = None, no_input = False
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '.', config_file = None, default_config = False, password = None
directory = None, skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_specify_output_dir.py::test_api_invocation
test_specify_output_dir.py::test_api_invocation
mocker =
template = '/tmp/pytest-of-root/pytest-0/test_api_invocation0/template'
output_dir = '/tmp/pytest-of-root/pytest-0/test_api_invocation0/output'
context = {'cookiecutter': {'email': 'raphael@hackebrot.de', 'full_name': 'Raphael Pierzina', 'github_username': 'hackebrot', 'version': '0.1.0'}}
def test_api_invocation(mocker, template, output_dir, context):
"""Verify output dir location is correctly passed."""
mock_gen_files = mocker.patch('cookiecutter.main.generate_files')
> main.cookiecutter(template, output_dir=output_dir)
tests/test_specify_output_dir.py:52:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '/tmp/pytest-of-root/pytest-0/test_api_invocation0/template'
checkout = None, no_input = False, extra_context = None, replay = None
overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_api_invocation0/output'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_specify_output_dir.py::test_default_output_dir
test_specify_output_dir.py::test_default_output_dir
mocker =
template = '/tmp/pytest-of-root/pytest-0/test_default_output_dir0/template'
context = {'cookiecutter': {'email': 'raphael@hackebrot.de', 'full_name': 'Raphael Pierzina', 'github_username': 'hackebrot', 'version': '0.1.0'}}
def test_default_output_dir(mocker, template, context):
"""Verify default output dir is current working folder."""
mock_gen_files = mocker.patch('cookiecutter.main.generate_files')
> main.cookiecutter(template)
tests/test_specify_output_dir.py:69:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = '/tmp/pytest-of-root/pytest-0/test_default_output_dir0/template'
checkout = None, no_input = False, extra_context = None, replay = None
overwrite_if_exists = False, output_dir = '.', config_file = None
default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_templates.py::test_build_templates[include]
test_templates.py::test_build_templates[include]
template = 'include'
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_include_0/templates'
@pytest.mark.parametrize("template", ["include", "no-templates", "extends", "super"])
def test_build_templates(template, output_dir):
"""
Verify Templates Design keywords.
no-templates is a compatibility tests for repo without `templates` directory
"""
> project_dir = main.cookiecutter(
f'tests/test-templates/{template}',
no_input=True,
output_dir=output_dir,
)
tests/test_templates.py:28:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-templates/include', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_include_0/templates'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_templates.py::test_build_templates[no-templates]
test_templates.py::test_build_templates[no-templates]
template = 'no-templates'
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_no_templa0/templates'
@pytest.mark.parametrize("template", ["include", "no-templates", "extends", "super"])
def test_build_templates(template, output_dir):
"""
Verify Templates Design keywords.
no-templates is a compatibility tests for repo without `templates` directory
"""
> project_dir = main.cookiecutter(
f'tests/test-templates/{template}',
no_input=True,
output_dir=output_dir,
)
tests/test_templates.py:28:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-templates/no-templates', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_no_templa0/templates'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_templates.py::test_build_templates[extends]
test_templates.py::test_build_templates[extends]
template = 'extends'
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_extends_0/templates'
@pytest.mark.parametrize("template", ["include", "no-templates", "extends", "super"])
def test_build_templates(template, output_dir):
"""
Verify Templates Design keywords.
no-templates is a compatibility tests for repo without `templates` directory
"""
> project_dir = main.cookiecutter(
f'tests/test-templates/{template}',
no_input=True,
output_dir=output_dir,
)
tests/test_templates.py:28:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-templates/extends', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_extends_0/templates'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_templates.py::test_build_templates[super]
test_templates.py::test_build_templates[super]
template = 'super'
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_super_0/templates'
@pytest.mark.parametrize("template", ["include", "no-templates", "extends", "super"])
def test_build_templates(template, output_dir):
"""
Verify Templates Design keywords.
no-templates is a compatibility tests for repo without `templates` directory
"""
> project_dir = main.cookiecutter(
f'tests/test-templates/{template}',
no_input=True,
output_dir=output_dir,
)
tests/test_templates.py:28:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
template = 'tests/test-templates/super', checkout = None, no_input = True
extra_context = None, replay = None, overwrite_if_exists = False
output_dir = '/tmp/pytest-of-root/pytest-0/test_build_templates_super_0/templates'
config_file = None, default_config = False, password = None, directory = None
skip_if_file_exists = False, accept_hooks = True
keep_project_on_failure = False
def cookiecutter(template, checkout=None, no_input=False, extra_context=None, replay=None, overwrite_if_exists=False, output_dir='.', config_file=None, default_config=False, password=None, directory=None, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""
Run Cookiecutter just as if using it from the command line.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input.
Use default values for template parameters taken from `cookiecutter.json`, user
config and `extra_dict`. Force a refresh of cached resources.
:param extra_context: A dictionary of context that overrides default
and user configuration.
:param replay: Do not prompt for input, instead read from saved json. If
``True`` read from the ``replay_dir``.
if it exists
:param overwrite_if_exists: Overwrite the contents of the output directory
if it exists.
:param output_dir: Where to output the generated project dir into.
:param config_file: User configuration file path.
:param default_config: Use default values rather than a config file.
:param password: The password to use when extracting the repository.
:param directory: Relative path to a cookiecutter template in a repository.
:param skip_if_file_exists: Skip the files in the corresponding directories
if they already exist.
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
:raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
if replay and no_input:
raise InvalidModeException(
'You cannot use both replay and no_input flags at the same time.'
)
# Get user config from ~/.cookiecutterrc or equivalent
config_dict = get_user_config(
config_file=config_file,
default_config=default_config,
)
# Get the repo dir, where the cookiecutter template source is stored
repo_dir, cleanup = determine_repo_dir(
template=template,
> abbreviations=config_dict['abbreviations'],
clone_to_dir=config_dict['cookiecutters_dir'],
checkout=checkout,
no_input=no_input,
password=password,
directory=directory
)
E TypeError: 'NoneType' object is not subscriptable
cookiecutter/main.py:65: TypeError
test_time_extension.py::test_utc_default_datetime_format
environment =
def test_utc_default_datetime_format(environment):
"""Verify default datetime format can be parsed."""
> template = environment.from_string("{% now 'utc' %}")
tests/test_time_extension.py:31:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_time_extension.py::test_accept_valid_timezones[utc]
test_time_extension.py::test_accept_valid_timezones[utc]
environment =
valid_tz = 'utc'
@pytest.mark.parametrize("valid_tz", ['utc', 'local', 'Europe/Berlin'])
def test_accept_valid_timezones(environment, valid_tz):
"""Verify that valid timezones are accepted."""
> template = environment.from_string(f"{{% now '{valid_tz}', '%Y-%m' %}}")
tests/test_time_extension.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_time_extension.py::test_accept_valid_timezones[local]
test_time_extension.py::test_accept_valid_timezones[local]
environment =
valid_tz = 'local'
@pytest.mark.parametrize("valid_tz", ['utc', 'local', 'Europe/Berlin'])
def test_accept_valid_timezones(environment, valid_tz):
"""Verify that valid timezones are accepted."""
> template = environment.from_string(f"{{% now '{valid_tz}', '%Y-%m' %}}")
tests/test_time_extension.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
Berlin]
Berlin]
environment =
valid_tz = 'Europe/Berlin'
@pytest.mark.parametrize("valid_tz", ['utc', 'local', 'Europe/Berlin'])
def test_accept_valid_timezones(environment, valid_tz):
"""Verify that valid timezones are accepted."""
> template = environment.from_string(f"{{% now '{valid_tz}', '%Y-%m' %}}")
tests/test_time_extension.py:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_time_extension.py::test_environment_datetime_format
environment =
def test_environment_datetime_format(environment):
"""Verify datetime format can be parsed from environment."""
environment.datetime_format = '%a, %d %b %Y %H:%M:%S'
> template = environment.from_string("{% now 'utc' %}")
tests/test_time_extension.py:48:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_time_extension.py::test_add_time
test_time_extension.py::test_add_time
environment =
def test_add_time(environment):
"""Verify that added time offset can be parsed."""
environment.datetime_format = '%a, %d %b %Y %H:%M:%S'
> template = environment.from_string("{% now 'utc' + 'hours=2,seconds=30' %}")
tests/test_time_extension.py:57:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_time_extension.py::test_substract_time
test_time_extension.py::test_substract_time
environment =
def test_substract_time(environment):
"""Verify that substracted time offset can be parsed."""
environment.datetime_format = '%a, %d %b %Y %H:%M:%S'
> template = environment.from_string("{% now 'utc' - 'minutes=11' %}")
tests/test_time_extension.py:66:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_time_extension.py::test_offset_with_format
environment =
def test_offset_with_format(environment):
"""Verify that offset works together with datetime format."""
environment.datetime_format = '%d %b %Y %H:%M:%S'
> template = environment.from_string(
"{% now 'utc' - 'days=2,minutes=33,seconds=1', '%d %b %Y %H:%M:%S' %}"
)
tests/test_time_extension.py:75:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/jinja2/environment.py:1108: in from_string
return cls.from_code(self, self.compile(source), gs, None)
.venv/lib/python3.10/site-packages/jinja2/environment.py:768: in compile
self.handle_exception(source=source_hint)
.venv/lib/python3.10/site-packages/jinja2/environment.py:939: in handle_exception
raise rewrite_traceback_stack(source=source)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got 'now'
:1: TemplateSyntaxError
test_utils.py::test_force_delete
test_utils.py::test_force_delete
mocker =
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_force_delete0')
def test_force_delete(mocker, tmp_path):
"""Verify `utils.force_delete` makes files writable."""
ro_file = Path(tmp_path, 'bar')
ro_file.write_text("Test data")
make_readonly(ro_file)
rmtree = mocker.Mock()
utils.force_delete(rmtree, ro_file, sys.exc_info())
> assert (ro_file.stat().st_mode & stat.S_IWRITE) == stat.S_IWRITE
E AssertionError: assert (33060 & 128) == 128
E + where 33060 = os.stat_result(st_mode=33060, st_ino=3798, st_dev=17, st_nlink=1, st_uid=0, st_gid=0, st_size=9, st_atime=1732854821, st_mtime=1732854821, st_ctime=1732854821).st_mode
E + where os.stat_result(st_mode=33060, st_ino=3798, st_dev=17, st_nlink=1, st_uid=0, st_gid=0, st_size=9, st_atime=1732854821, st_mtime=1732854821, st_ctime=1732854821) = stat()
E + where stat = PosixPath('/tmp/pytest-of-root/pytest-0/test_force_delete0/bar').stat
E + and 128 = stat.S_IWRITE
E + and 128 = stat.S_IWRITE
tests/test_utils.py:27: AssertionError
test_utils.py::test_rmtree
test_utils.py::test_rmtree
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_rmtree0')
def test_rmtree(tmp_path):
"""Verify `utils.rmtree` remove files marked as read-only."""
file_path = Path(tmp_path, "bar")
file_path.write_text("Test data")
make_readonly(file_path)
utils.rmtree(tmp_path)
> assert not Path(tmp_path).exists()
E AssertionError: assert not True
E + where True = exists()
E + where exists = PosixPath('/tmp/pytest-of-root/pytest-0/test_rmtree0').exists
E + where PosixPath('/tmp/pytest-of-root/pytest-0/test_rmtree0') = Path(PosixPath('/tmp/pytest-of-root/pytest-0/test_rmtree0'))
tests/test_utils.py:41: AssertionError
test_utils.py::test_make_sure_path_exists
test_utils.py::test_make_sure_path_exists
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_make_sure_path_exists0')
def test_make_sure_path_exists(tmp_path):
"""Verify correct True/False response from `utils.make_sure_path_exists`.
Should return True if directory exist or created.
Should return False if impossible to create directory (for example protected)
"""
existing_directory = tmp_path
directory_to_create = Path(tmp_path, "not_yet_created")
utils.make_sure_path_exists(existing_directory)
utils.make_sure_path_exists(directory_to_create)
# Ensure by base system methods.
assert existing_directory.is_dir()
assert existing_directory.exists()
> assert directory_to_create.is_dir()
E AssertionError: assert False
E + where False = is_dir()
E + where is_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_make_sure_path_exists0/not_yet_created').is_dir
tests/test_utils.py:59: AssertionError
test_utils.py::test_make_sure_path_exists_correctly_handle_os_error
test_utils.py::test_make_sure_path_exists_correctly_handle_os_error
mocker =
def test_make_sure_path_exists_correctly_handle_os_error(mocker):
"""Verify correct True/False response from `utils.make_sure_path_exists`.
Should return True if directory exist or created.
Should return False if impossible to create directory (for example protected)
"""
mocker.patch("pathlib.Path.mkdir", side_effect=OSError)
> with pytest.raises(OSError) as err:
E Failed: DID NOT RAISE
tests/test_utils.py:70: Failed
test_utils.py::test_work_in
test_utils.py::test_work_in
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_work_in0')
def test_work_in(tmp_path):
"""Verify returning to original folder after `utils.work_in` use."""
cwd = Path.cwd()
ch_to = tmp_path
assert ch_to != Path.cwd()
# Under context manager we should work in tmp_path.
> with utils.work_in(ch_to):
tests/test_utils.py:83:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
def __enter__(self):
# do not keep args and kwds alive unnecessarily
# they are only needed for recreation, which is not possible anymore
del self.args, self.kwds, self.func
try:
> return next(self.gen)
E TypeError: 'NoneType' object is not an iterator
/usr/lib/python3.10/contextlib.py:135: TypeError
test_utils.py::test_work_in_without_path
test_utils.py::test_work_in_without_path
def test_work_in_without_path():
"""Folder is not changed if no path provided."""
cwd = Path.cwd()
> with utils.work_in():
tests/test_utils.py:94:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
def __enter__(self):
# do not keep args and kwds alive unnecessarily
# they are only needed for recreation, which is not possible anymore
del self.args, self.kwds, self.func
try:
> return next(self.gen)
E TypeError: 'NoneType' object is not an iterator
/usr/lib/python3.10/contextlib.py:135: TypeError
test_utils.py::test_create_tmp_repo_dir
test_utils.py::test_create_tmp_repo_dir
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-0/test_create_tmp_repo_dir0')
def test_create_tmp_repo_dir(tmp_path):
"""Verify `utils.create_tmp_repo_dir` creates a copy."""
repo_dir = Path(tmp_path) / 'bar'
repo_dir.mkdir()
subdirs = ('foo', 'bar', 'foobar')
for name in subdirs:
(repo_dir / name).mkdir()
new_repo_dir = utils.create_tmp_repo_dir(repo_dir)
> assert new_repo_dir.exists()
E AttributeError: 'NoneType' object has no attribute 'exists'
tests/test_utils.py:110: AttributeError
test_clone.py::test_clone_should_rstrip_trailing_slash_in_repo_url
test_clone.py::test_clone_should_rstrip_trailing_slash_in_repo_url
self =
args = (['git', 'clone', 'https://github.com/foo/bar'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), 'stderr': -2}
expected = call('', (['git', 'clone', 'https://github.com/foo/bar'],), {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), 'stderr': -2})
actual = call('', (['git', 'clone', 'https://github.com/foo/bar', 'bar'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir', 'stderr': -2})
_error_message = ._error_message at 0x7f6a6efeab90>
cause = None
def assert_called_with(self, /, *args, **kwargs):
"""assert that the last call was made with the specified arguments.
Raises an AssertionError if the args and keyword args passed in are
different to the last call to the mock."""
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
% (expected, actual))
raise AssertionError(error_message)
def _error_message():
msg = self._format_mock_failure_message(args, kwargs)
return msg
expected = self._call_matcher(_Call((args, kwargs), two=True))
actual = self._call_matcher(self.call_args)
if actual != expected:
cause = expected if isinstance(expected, Exception) else None
> raise AssertionError(_error_message()) from cause
E AssertionError: expected call not found.
E Expected: check_output(['git', 'clone', 'https://github.com/foo/bar'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), stderr=-2)
E Actual: check_output(['git', 'clone', 'https://github.com/foo/bar', 'bar'], cwd='/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir', stderr=-2)
/usr/lib/python3.10/unittest/mock.py:929: AssertionError
During handling of the above exception, another exception occurred:
self =
args = (['git', 'clone', 'https://github.com/foo/bar'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), 'stderr': -2}
def assert_called_once_with(self, /, *args, **kwargs):
"""assert that the mock was called exactly once and that that call was
with the specified arguments."""
if not self.call_count == 1:
msg = ("Expected '%s' to be called once. Called %s times.%s"
% (self._mock_name or 'mock',
self.call_count,
self._calls_repr()))
raise AssertionError(msg)
> return self.assert_called_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: check_output(['git', 'clone', 'https://github.com/foo/bar'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), stderr=-2)
E Actual: check_output(['git', 'clone', 'https://github.com/foo/bar', 'bar'], cwd='/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir', stderr=-2)
E
E pytest introspection follows:
E
E Args:
E assert (['git', 'clone', 'https://github.com/foo/bar', 'bar'],) == (['git', 'clone', 'https://github.com/foo/bar'],)
E
E At index 0 diff: ['git', 'clone', 'https://github.com/foo/bar', 'bar'] != ['git', 'clone', 'https://github.com/foo/bar']
E
E Full diff:
E (
E [
E 'git',
E 'clone',
E 'https://github.com/foo/bar',
E + 'bar',
E ],
E )
E Kwargs:
E assert {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir', 'stderr': -2} == {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), 'stderr': -2}
E
E Common items:
E {'stderr': -2}
E Differing items:
E {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'} != {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir')}
E
E Full diff:
E {
E - 'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'),
E ? ---------- -
E + 'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir',
E 'stderr': -2,
E }
/usr/lib/python3.10/unittest/mock.py:941: AssertionError
During handling of the above exception, another exception occurred:
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir')
def test_clone_should_rstrip_trailing_slash_in_repo_url(mocker, clone_dir):
"""In `clone()`, repo URL's trailing slash should be stripped if one is \
present."""
mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
mock_subprocess = mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
)
vcs.clone('https://github.com/foo/bar/', clone_to_dir=clone_dir, no_input=True)
> mock_subprocess.assert_called_once_with(
['git', 'clone', 'https://github.com/foo/bar'],
cwd=clone_dir,
stderr=subprocess.STDOUT,
)
tests/vcs/test_clone.py:34:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = (['git', 'clone', 'https://github.com/foo/bar'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), 'stderr': -2}
def assert_called_once_with(*args, **kwargs):
> return mock.assert_called_once_with(*args, **kwargs)
E AssertionError: expected call not found.
E Expected: check_output(['git', 'clone', 'https://github.com/foo/bar'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), stderr=-2)
E Actual: check_output(['git', 'clone', 'https://github.com/foo/bar', 'bar'], cwd='/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir', stderr=-2)
E
E pytest introspection follows:
E
E Args:
E assert (['git', 'clone', 'https://github.com/foo/bar', 'bar'],) == (['git', 'clone', 'https://github.com/foo/bar'],)
E
E At index 0 diff: ['git', 'clone', 'https://github.com/foo/bar', 'bar'] != ['git', 'clone', 'https://github.com/foo/bar']
E
E Full diff:
E (
E [
E 'git',
E 'clone',
E 'https://github.com/foo/bar',
E + 'bar',
E ],
E )
E Kwargs:
E assert {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir', 'stderr': -2} == {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'), 'stderr': -2}
E
E Common items:
E {'stderr': -2}
E Differing items:
E {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'} != {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir')}
E
E Full diff:
E {
E - 'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir'),
E ? ---------- -
E + 'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_rstrip_trail0/clone_dir',
E 'stderr': -2,
E }
/usr/lib/python3.10/unittest/mock.py:213: AssertionError
world.git-world]
world.git-world]
self =
args = (['git', 'clone', 'https://github.com/hello/world.git'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), 'stderr': -2}
expected = call('', (['git', 'clone', 'https://github.com/hello/world.git'],), {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), 'stderr': -2})
cause = None
actual = [call('', (['git', 'clone', 'https://github.com/hello/world.git', 'world'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir', 'stderr': -2}), call('', (['git', 'checkout', 'foobar'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir/world', 'stderr': -2})]
expected_string = "check_output(['git', 'clone', 'https://github.com/hello/world.git'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), stderr=-2)"
def assert_any_call(self, /, *args, **kwargs):
"""assert the mock has been called with the specified arguments.
The assert passes if the mock has *ever* been called, unlike
`assert_called_with` and `assert_called_once_with` that only pass if
the call is the most recent one."""
expected = self._call_matcher(_Call((args, kwargs), two=True))
cause = expected if isinstance(expected, Exception) else None
actual = [self._call_matcher(c) for c in self.call_args_list]
if cause or expected not in _AnyComparer(actual):
expected_string = self._format_mock_call_signature(args, kwargs)
> raise AssertionError(
'%s call not found' % expected_string
) from cause
E AssertionError: check_output(['git', 'clone', 'https://github.com/hello/world.git'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), stderr=-2) call not found
/usr/lib/python3.10/unittest/mock.py:1000: AssertionError
During handling of the above exception, another exception occurred:
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir')
repo_type = 'git', repo_url = 'https://github.com/hello/world.git'
repo_name = 'world'
@pytest.mark.parametrize(
'repo_type, repo_url, repo_name',
[
('git', 'https://github.com/hello/world.git', 'world'),
('hg', 'https://bitbucket.org/foo/bar', 'bar'),
('git', 'git@host:gitoliterepo', 'gitoliterepo'),
('git', 'git@gitlab.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
('git', 'git@github.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
],
)
def test_clone_should_invoke_vcs_command(
mocker, clone_dir, repo_type, repo_url, repo_name
):
"""When `clone()` is called with a git/hg repo, the corresponding VCS \
command should be run via `subprocess.check_output()`.
This should take place:
* In the correct dir
* With the correct args.
"""
mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
mock_subprocess = mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
)
expected_repo_dir = os.path.normpath(os.path.join(clone_dir, repo_name))
branch = 'foobar'
repo_dir = vcs.clone(
repo_url, checkout=branch, clone_to_dir=clone_dir, no_input=True
)
assert repo_dir == expected_repo_dir
> mock_subprocess.assert_any_call(
[repo_type, 'clone', repo_url], cwd=clone_dir, stderr=subprocess.STDOUT
)
tests/vcs/test_clone.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = (['git', 'clone', 'https://github.com/hello/world.git'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), 'stderr': -2}
def assert_any_call(*args, **kwargs):
> return mock.assert_any_call(*args, **kwargs)
E AssertionError: check_output(['git', 'clone', 'https://github.com/hello/world.git'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), stderr=-2) call not found
E
E pytest introspection follows:
E
E Args:
E assert (['git', 'checkout', 'foobar'],) == (['git', 'clone', 'https://github.com/hello/world.git'],)
E
E At index 0 diff: ['git', 'checkout', 'foobar'] != ['git', 'clone', 'https://github.com/hello/world.git']
E
E Full diff:
E (
E [
E 'git',
E - 'clone',
E - 'https://github.com/hello/world.git',
E + 'checkout',
E + 'foobar',
E ],
E )
E Kwargs:
E assert {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir/world', 'stderr': -2} == {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'), 'stderr': -2}
E
E Common items:
E {'stderr': -2}
E Differing items:
E {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir/world'} != {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir')}
E
E Full diff:
E {
E - 'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir'),
E ? ---------- -
E + 'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c0/clone_dir/world',
E ? ++++++
E 'stderr': -2,
E }
/usr/lib/python3.10/unittest/mock.py:217: AssertionError
bar-bar]
bar-bar]
self =
args = (['hg', 'clone', 'https://bitbucket.org/foo/bar'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), 'stderr': -2}
expected = call('', (['hg', 'clone', 'https://bitbucket.org/foo/bar'],), {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), 'stderr': -2})
cause = None
actual = [call('', (['hg', 'clone', 'https://bitbucket.org/foo/bar'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir', 'stderr': -2}), call('', (['hg', 'update', 'foobar'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir/bar', 'stderr': -2})]
expected_string = "check_output(['hg', 'clone', 'https://bitbucket.org/foo/bar'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), stderr=-2)"
def assert_any_call(self, /, *args, **kwargs):
"""assert the mock has been called with the specified arguments.
The assert passes if the mock has *ever* been called, unlike
`assert_called_with` and `assert_called_once_with` that only pass if
the call is the most recent one."""
expected = self._call_matcher(_Call((args, kwargs), two=True))
cause = expected if isinstance(expected, Exception) else None
actual = [self._call_matcher(c) for c in self.call_args_list]
if cause or expected not in _AnyComparer(actual):
expected_string = self._format_mock_call_signature(args, kwargs)
> raise AssertionError(
'%s call not found' % expected_string
) from cause
E AssertionError: check_output(['hg', 'clone', 'https://bitbucket.org/foo/bar'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), stderr=-2) call not found
/usr/lib/python3.10/unittest/mock.py:1000: AssertionError
During handling of the above exception, another exception occurred:
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir')
repo_type = 'hg', repo_url = 'https://bitbucket.org/foo/bar', repo_name = 'bar'
@pytest.mark.parametrize(
'repo_type, repo_url, repo_name',
[
('git', 'https://github.com/hello/world.git', 'world'),
('hg', 'https://bitbucket.org/foo/bar', 'bar'),
('git', 'git@host:gitoliterepo', 'gitoliterepo'),
('git', 'git@gitlab.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
('git', 'git@github.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
],
)
def test_clone_should_invoke_vcs_command(
mocker, clone_dir, repo_type, repo_url, repo_name
):
"""When `clone()` is called with a git/hg repo, the corresponding VCS \
command should be run via `subprocess.check_output()`.
This should take place:
* In the correct dir
* With the correct args.
"""
mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
mock_subprocess = mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
)
expected_repo_dir = os.path.normpath(os.path.join(clone_dir, repo_name))
branch = 'foobar'
repo_dir = vcs.clone(
repo_url, checkout=branch, clone_to_dir=clone_dir, no_input=True
)
assert repo_dir == expected_repo_dir
> mock_subprocess.assert_any_call(
[repo_type, 'clone', repo_url], cwd=clone_dir, stderr=subprocess.STDOUT
)
tests/vcs/test_clone.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = (['hg', 'clone', 'https://bitbucket.org/foo/bar'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), 'stderr': -2}
def assert_any_call(*args, **kwargs):
> return mock.assert_any_call(*args, **kwargs)
E AssertionError: check_output(['hg', 'clone', 'https://bitbucket.org/foo/bar'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), stderr=-2) call not found
E
E pytest introspection follows:
E
E Args:
E assert (['hg', 'update', 'foobar'],) == (['hg', 'clone', 'https://bitbucket.org/foo/bar'],)
E
E At index 0 diff: ['hg', 'update', 'foobar'] != ['hg', 'clone', 'https://bitbucket.org/foo/bar']
E
E Full diff:
E (
E [
E 'hg',
E - 'clone',
E - 'https://bitbucket.org/foo/bar',
E + 'update',
E + 'foobar',
E ],
E )
E Kwargs:
E assert {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir/bar', 'stderr': -2} == {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'), 'stderr': -2}
E
E Common items:
E {'stderr': -2}
E Differing items:
E {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir/bar'} != {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir')}
E
E Full diff:
E {
E - 'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir'),
E ? ---------- -
E + 'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c1/clone_dir/bar',
E ? ++++
E 'stderr': -2,
E }
/usr/lib/python3.10/unittest/mock.py:217: AssertionError
test_clone.py::test_clone_should_invoke_vcs_command[git-git@host:gitoliterepo-gitoliterepo]
test_clone.py::test_clone_should_invoke_vcs_command[git-git@host:gitoliterepo-gitoliterepo]
self =
args = (['git', 'clone', 'git@host:gitoliterepo'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), 'stderr': -2}
expected = call('', (['git', 'clone', 'git@host:gitoliterepo'],), {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), 'stderr': -2})
cause = None
actual = [call('', (['git', 'clone', 'git@host:gitoliterepo', 'gitoliterepo'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir', 'stderr': -2}), call('', (['git', 'checkout', 'foobar'],), {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir/gitoliterepo', 'stderr': -2})]
expected_string = "check_output(['git', 'clone', 'git@host:gitoliterepo'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), stderr=-2)"
def assert_any_call(self, /, *args, **kwargs):
"""assert the mock has been called with the specified arguments.
The assert passes if the mock has *ever* been called, unlike
`assert_called_with` and `assert_called_once_with` that only pass if
the call is the most recent one."""
expected = self._call_matcher(_Call((args, kwargs), two=True))
cause = expected if isinstance(expected, Exception) else None
actual = [self._call_matcher(c) for c in self.call_args_list]
if cause or expected not in _AnyComparer(actual):
expected_string = self._format_mock_call_signature(args, kwargs)
> raise AssertionError(
'%s call not found' % expected_string
) from cause
E AssertionError: check_output(['git', 'clone', 'git@host:gitoliterepo'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), stderr=-2) call not found
/usr/lib/python3.10/unittest/mock.py:1000: AssertionError
During handling of the above exception, another exception occurred:
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir')
repo_type = 'git', repo_url = 'git@host:gitoliterepo'
repo_name = 'gitoliterepo'
@pytest.mark.parametrize(
'repo_type, repo_url, repo_name',
[
('git', 'https://github.com/hello/world.git', 'world'),
('hg', 'https://bitbucket.org/foo/bar', 'bar'),
('git', 'git@host:gitoliterepo', 'gitoliterepo'),
('git', 'git@gitlab.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
('git', 'git@github.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
],
)
def test_clone_should_invoke_vcs_command(
mocker, clone_dir, repo_type, repo_url, repo_name
):
"""When `clone()` is called with a git/hg repo, the corresponding VCS \
command should be run via `subprocess.check_output()`.
This should take place:
* In the correct dir
* With the correct args.
"""
mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
mock_subprocess = mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
)
expected_repo_dir = os.path.normpath(os.path.join(clone_dir, repo_name))
branch = 'foobar'
repo_dir = vcs.clone(
repo_url, checkout=branch, clone_to_dir=clone_dir, no_input=True
)
assert repo_dir == expected_repo_dir
> mock_subprocess.assert_any_call(
[repo_type, 'clone', repo_url], cwd=clone_dir, stderr=subprocess.STDOUT
)
tests/vcs/test_clone.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = (['git', 'clone', 'git@host:gitoliterepo'],)
kwargs = {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), 'stderr': -2}
def assert_any_call(*args, **kwargs):
> return mock.assert_any_call(*args, **kwargs)
E AssertionError: check_output(['git', 'clone', 'git@host:gitoliterepo'], cwd=PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), stderr=-2) call not found
E
E pytest introspection follows:
E
E Args:
E assert (['git', 'checkout', 'foobar'],) == (['git', 'clone', 'git@host:gitoliterepo'],)
E
E At index 0 diff: ['git', 'checkout', 'foobar'] != ['git', 'clone', 'git@host:gitoliterepo']
E
E Full diff:
E (
E [
E 'git',
E - 'clone',
E - 'git@host:gitoliterepo',
E + 'checkout',
E + 'foobar',
E ],
E )
E Kwargs:
E assert {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir/gitoliterepo', 'stderr': -2} == {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'), 'stderr': -2}
E
E Common items:
E {'stderr': -2}
E Differing items:
E {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir/gitoliterepo'} != {'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir')}
E
E Full diff:
E {
E - 'cwd': PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir'),
E ? ---------- -
E + 'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c2/clone_dir/gitoliterepo',
E ? +++++++++++++
E 'stderr': -2,
E }
/usr/lib/python3.10/unittest/mock.py:217: AssertionError
cookiecutter.git-cookiecutter]
cookiecutter.git-cookiecutter]
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c3/clone_dir')
repo_type = 'git', repo_url = 'git@gitlab.com:cookiecutter/cookiecutter.git'
repo_name = 'cookiecutter'
@pytest.mark.parametrize(
'repo_type, repo_url, repo_name',
[
('git', 'https://github.com/hello/world.git', 'world'),
('hg', 'https://bitbucket.org/foo/bar', 'bar'),
('git', 'git@host:gitoliterepo', 'gitoliterepo'),
('git', 'git@gitlab.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
('git', 'git@github.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
],
)
def test_clone_should_invoke_vcs_command(
mocker, clone_dir, repo_type, repo_url, repo_name
):
"""When `clone()` is called with a git/hg repo, the corresponding VCS \
command should be run via `subprocess.check_output()`.
This should take place:
* In the correct dir
* With the correct args.
"""
mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
mock_subprocess = mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
)
expected_repo_dir = os.path.normpath(os.path.join(clone_dir, repo_name))
branch = 'foobar'
repo_dir = vcs.clone(
repo_url, checkout=branch, clone_to_dir=clone_dir, no_input=True
)
> assert repo_dir == expected_repo_dir
E AssertionError: assert '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c3/clone_dir/cookiecutter/cookiecutter' == '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c3/clone_dir/cookiecutter'
E
E - /tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c3/clone_dir/cookiecutter
E + /tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c3/clone_dir/cookiecutter/cookiecutter
E ? +++++++++++++
tests/vcs/test_clone.py:121: AssertionError
cookiecutter.git-cookiecutter]
cookiecutter.git-cookiecutter]
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c4/clone_dir')
repo_type = 'git', repo_url = 'git@github.com:cookiecutter/cookiecutter.git'
repo_name = 'cookiecutter'
@pytest.mark.parametrize(
'repo_type, repo_url, repo_name',
[
('git', 'https://github.com/hello/world.git', 'world'),
('hg', 'https://bitbucket.org/foo/bar', 'bar'),
('git', 'git@host:gitoliterepo', 'gitoliterepo'),
('git', 'git@gitlab.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
('git', 'git@github.com:cookiecutter/cookiecutter.git', 'cookiecutter'),
],
)
def test_clone_should_invoke_vcs_command(
mocker, clone_dir, repo_type, repo_url, repo_name
):
"""When `clone()` is called with a git/hg repo, the corresponding VCS \
command should be run via `subprocess.check_output()`.
This should take place:
* In the correct dir
* With the correct args.
"""
mocker.patch('cookiecutter.vcs.is_vcs_installed', autospec=True, return_value=True)
mock_subprocess = mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
)
expected_repo_dir = os.path.normpath(os.path.join(clone_dir, repo_name))
branch = 'foobar'
repo_dir = vcs.clone(
repo_url, checkout=branch, clone_to_dir=clone_dir, no_input=True
)
> assert repo_dir == expected_repo_dir
E AssertionError: assert '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c4/clone_dir/cookiecutter/cookiecutter' == '/tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c4/clone_dir/cookiecutter'
E
E - /tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c4/clone_dir/cookiecutter
E + /tmp/pytest-of-root/pytest-0/test_clone_should_invoke_vcs_c4/clone_dir/cookiecutter/cookiecutter
E ? +++++++++++++
tests/vcs/test_clone.py:121: AssertionError
test_clone.py::test_clone_handles_branch_typo[error: pathspec 'unknown_branch' did not match any file(s) known to git]
test_clone.py::test_clone_handles_branch_typo[error: pathspec 'unknown_branch' did not match any file(s) known to git]
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_handles_branch_typo0/clone_dir')
error_message = b"error: pathspec 'unknown_branch' did not match any file(s) known to git"
@pytest.mark.parametrize(
'error_message',
[
b"error: pathspec 'unknown_branch' did not match any file(s) known to git",
b"hg: abort: unknown revision 'unknown_branch'!",
],
)
def test_clone_handles_branch_typo(mocker, clone_dir, error_message):
"""In `clone()`, branch not found errors should raise an \
appropriate exception."""
mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
side_effect=[subprocess.CalledProcessError(-1, 'cmd', output=error_message)],
)
repository_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin'
with pytest.raises(exceptions.RepositoryCloneFailed) as err:
vcs.clone(
repository_url,
clone_to_dir=str(clone_dir),
checkout='unknown_branch',
no_input=True,
)
> assert str(err.value) == (
'The unknown_branch branch of repository '
f'{repository_url} could not found, have you made a typo?'
)
E assert "Failed to clone repository https://github.com/pytest-dev/cookiecutter-pytest-plugin:\nerror: pathspec 'unknown_branch' did not match any file(s) known to git" == 'The unknown_branch branch of repository https://github.com/pytest-dev/cookiecutter-pytest-plugin could not found, have you made a typo?'
E
E - The unknown_branch branch of repository https://github.com/pytest-dev/cookiecutter-pytest-plugin could not found, have you made a typo?
E + Failed to clone repository https://github.com/pytest-dev/cookiecutter-pytest-plugin:
E + error: pathspec 'unknown_branch' did not match any file(s) known to git
tests/vcs/test_clone.py:192: AssertionError
test_clone.py::test_clone_handles_branch_typo[hg: abort: unknown revision 'unknown_branch'!]
test_clone.py::test_clone_handles_branch_typo[hg: abort: unknown revision 'unknown_branch'!]
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_handles_branch_typo1/clone_dir')
error_message = b"hg: abort: unknown revision 'unknown_branch'!"
@pytest.mark.parametrize(
'error_message',
[
b"error: pathspec 'unknown_branch' did not match any file(s) known to git",
b"hg: abort: unknown revision 'unknown_branch'!",
],
)
def test_clone_handles_branch_typo(mocker, clone_dir, error_message):
"""In `clone()`, branch not found errors should raise an \
appropriate exception."""
mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
side_effect=[subprocess.CalledProcessError(-1, 'cmd', output=error_message)],
)
repository_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin'
with pytest.raises(exceptions.RepositoryCloneFailed) as err:
vcs.clone(
repository_url,
clone_to_dir=str(clone_dir),
checkout='unknown_branch',
no_input=True,
)
> assert str(err.value) == (
'The unknown_branch branch of repository '
f'{repository_url} could not found, have you made a typo?'
)
E assert "Failed to clone repository https://github.com/pytest-dev/cookiecutter-pytest-plugin:\nhg: abort: unknown revision 'unknown_branch'!" == 'The unknown_branch branch of repository https://github.com/pytest-dev/cookiecutter-pytest-plugin could not found, have you made a typo?'
E
E - The unknown_branch branch of repository https://github.com/pytest-dev/cookiecutter-pytest-plugin could not found, have you made a typo?
E + Failed to clone repository https://github.com/pytest-dev/cookiecutter-pytest-plugin:
E + hg: abort: unknown revision 'unknown_branch'!
tests/vcs/test_clone.py:192: AssertionError
test_clone.py::test_clone_unknown_subprocess_error
test_clone.py::test_clone_unknown_subprocess_error
repo_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin'
checkout = None
clone_to_dir = '/tmp/pytest-of-root/pytest-0/test_clone_unknown_subprocess_0/clone_dir'
no_input = True
def clone(repo_url: str, checkout: Optional[str]=None, clone_to_dir: 'os.PathLike[str]'='.', no_input: bool=False):
"""Clone a repo to the current directory.
:param repo_url: Repo URL of unknown type.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param clone_to_dir: The directory to clone to.
Defaults to the current directory.
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:returns: str with path to the new directory of the repository.
:raises: VCSNotInstalled if the required VCS is not installed
RepositoryNotFound if the repository cannot be found
RepositoryCloneFailed if the repository cannot be cloned
"""
# Ensure clone_to_dir exists
clone_to_dir = os.path.expanduser(clone_to_dir)
clone_to_dir = os.path.normpath(clone_to_dir)
make_sure_path_exists(clone_to_dir)
# Get repo type and url
repo_type, repo_url = identify_repo(repo_url)
# Check if VCS is installed
if not is_vcs_installed(repo_type):
raise VCSNotInstalled(f'{repo_type} is not installed.')
repo_url = repo_url.rstrip('/')
if '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
repo_name = repo_url.rsplit(':', 1)[-1]
else:
repo_name = repo_url.rsplit('/', 1)[-1]
if repo_type == 'git':
repo_name = repo_name.rsplit('.git', 1)[0]
elif repo_type == 'hg':
repo_name = repo_name.rsplit('.hg', 1)[0]
# Remove existing repo if no_input=True, otherwise prompt
repo_dir = os.path.join(clone_to_dir, repo_name)
if os.path.exists(repo_dir):
if no_input:
logger.debug('Removing %s', repo_dir)
subprocess.check_output(['rm', '-rf', repo_dir])
else:
if not prompt_and_delete(repo_dir):
return repo_dir
# Clone the repo
clone_cmd = [repo_type, 'clone', repo_url]
if repo_type == 'git':
clone_cmd.append(repo_name)
logger.debug('Running command: %s', ' '.join(clone_cmd))
try:
> subprocess.check_output(clone_cmd, cwd=str(clone_to_dir), stderr=subprocess.STDOUT)
cookiecutter/vcs.py:107:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/unittest/mock.py:1114: in __call__
return self._mock_call(*args, **kwargs)
/usr/lib/python3.10/unittest/mock.py:1118: in _mock_call
return self._execute_mock_call(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
args = (['git', 'clone', 'https://github.com/pytest-dev/cookiecutter-pytest-plugin', 'cookiecutter-pytest-plugin'],)
kwargs = {'cwd': '/tmp/pytest-of-root/pytest-0/test_clone_unknown_subprocess_0/clone_dir', 'stderr': -2}
effect =
result = CalledProcessError(-1, 'cmd')
def _execute_mock_call(self, /, *args, **kwargs):
# separate from _increment_mock_call so that awaited functions are
# executed separately from their call, also AsyncMock overrides this method
effect = self.side_effect
if effect is not None:
if _is_exception(effect):
raise effect
elif not _callable(effect):
result = next(effect)
if _is_exception(result):
> raise result
E subprocess.CalledProcessError: Command 'cmd' died with .
/usr/lib/python3.10/unittest/mock.py:1177: CalledProcessError
The above exception was the direct cause of the following exception:
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_clone_unknown_subprocess_0/clone_dir')
def test_clone_unknown_subprocess_error(mocker, clone_dir):
"""In `clone()`, unknown subprocess errors should be raised."""
mocker.patch(
'cookiecutter.vcs.subprocess.check_output',
autospec=True,
side_effect=[
subprocess.CalledProcessError(-1, 'cmd', output=b'Something went wrong')
],
)
with pytest.raises(subprocess.CalledProcessError):
> vcs.clone(
'https://github.com/pytest-dev/cookiecutter-pytest-plugin',
clone_to_dir=str(clone_dir),
no_input=True,
)
tests/vcs/test_clone.py:209:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
repo_url = 'https://github.com/pytest-dev/cookiecutter-pytest-plugin'
checkout = None
clone_to_dir = '/tmp/pytest-of-root/pytest-0/test_clone_unknown_subprocess_0/clone_dir'
no_input = True
def clone(repo_url: str, checkout: Optional[str]=None, clone_to_dir: 'os.PathLike[str]'='.', no_input: bool=False):
"""Clone a repo to the current directory.
:param repo_url: Repo URL of unknown type.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param clone_to_dir: The directory to clone to.
Defaults to the current directory.
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:returns: str with path to the new directory of the repository.
:raises: VCSNotInstalled if the required VCS is not installed
RepositoryNotFound if the repository cannot be found
RepositoryCloneFailed if the repository cannot be cloned
"""
# Ensure clone_to_dir exists
clone_to_dir = os.path.expanduser(clone_to_dir)
clone_to_dir = os.path.normpath(clone_to_dir)
make_sure_path_exists(clone_to_dir)
# Get repo type and url
repo_type, repo_url = identify_repo(repo_url)
# Check if VCS is installed
if not is_vcs_installed(repo_type):
raise VCSNotInstalled(f'{repo_type} is not installed.')
repo_url = repo_url.rstrip('/')
if '@' in repo_url and ':' in repo_url:
# SSH URL format: [user@]host:path
repo_name = repo_url.rsplit(':', 1)[-1]
else:
repo_name = repo_url.rsplit('/', 1)[-1]
if repo_type == 'git':
repo_name = repo_name.rsplit('.git', 1)[0]
elif repo_type == 'hg':
repo_name = repo_name.rsplit('.hg', 1)[0]
# Remove existing repo if no_input=True, otherwise prompt
repo_dir = os.path.join(clone_to_dir, repo_name)
if os.path.exists(repo_dir):
if no_input:
logger.debug('Removing %s', repo_dir)
subprocess.check_output(['rm', '-rf', repo_dir])
else:
if not prompt_and_delete(repo_dir):
return repo_dir
# Clone the repo
clone_cmd = [repo_type, 'clone', repo_url]
if repo_type == 'git':
clone_cmd.append(repo_name)
logger.debug('Running command: %s', ' '.join(clone_cmd))
try:
subprocess.check_output(clone_cmd, cwd=str(clone_to_dir), stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
output = e.output.decode('utf-8')
if 'not found' in output.lower():
raise RepositoryNotFound(
f'The repository {repo_url} could not be found, '
'have you made a typo?'
) from e
> raise RepositoryCloneFailed(
f'Failed to clone repository {repo_url}:\n{output}'
) from e
E cookiecutter.exceptions.RepositoryCloneFailed: Failed to clone repository https://github.com/pytest-dev/cookiecutter-pytest-plugin:
E Something went wrong
cookiecutter/vcs.py:115: RepositoryCloneFailed
test_unzip.py::test_unzip_protected_local_file_user_password
test_unzip.py::test_unzip_protected_local_file_user_password
zip_uri = 'tests/files/protected-fake-repo-tmpl.zip', is_url = False
clone_to_dir = '/tmp/pytest-of-root/pytest-0/test_unzip_protected_local_fil3/clone_dir'
no_input = False, password = None
def unzip(zip_uri: str, is_url: bool, clone_to_dir: 'os.PathLike[str]'='.', no_input: bool=False, password: Optional[str]=None):
"""Download and unpack a zipfile at a given URI.
This will download the zipfile to the cookiecutter repository,
and unpack into a temporary directory.
:param zip_uri: The URI for the zipfile.
:param is_url: Is the zip URI a URL or a file?
:param clone_to_dir: The cookiecutter repository directory
to put the archive into.
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:param password: The password to use when unpacking the repository.
:raises: InvalidZipRepository if the zip file is not a valid cookiecutter template.
:returns: The path to the unpacked template.
"""
# Ensure clone_to_dir exists
clone_to_dir = os.path.expanduser(clone_to_dir)
clone_to_dir = os.path.normpath(clone_to_dir)
make_sure_path_exists(clone_to_dir)
if is_url:
# Build cache path and download if needed
zip_path = os.path.join(clone_to_dir, os.path.basename(zip_uri))
if os.path.exists(zip_path):
if no_input:
os.remove(zip_path)
else:
download = prompt_and_delete(zip_path)
if not download:
return zip_path
# Download the zip file
response = requests.get(zip_uri, stream=True)
response.raise_for_status()
with open(zip_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
else:
zip_path = os.path.abspath(zip_uri)
if not os.path.exists(zip_path):
raise InvalidZipRepository(
f'Zip file {zip_path} does not exist'
)
# Create a temporary directory for the unzipped contents
temp_dir = tempfile.mkdtemp(prefix='cookiecutter-', suffix='-unzip')
try:
# Get password if needed but not provided
pwd = password
if pwd is None:
pwd = os.environ.get('COOKIECUTTER_REPO_PASSWORD')
with ZipFile(zip_path) as zip_file:
# Check if zip file is empty
namelist = zip_file.namelist()
if not namelist:
raise InvalidZipRepository(
'Zip file is empty'
)
# Check if password protected
try:
# Try to read first file to check if password is needed
zip_file.read(namelist[0], pwd=pwd.encode('utf-8') if pwd else None)
except RuntimeError:
if no_input:
raise InvalidZipRepository(
'Zip file is password protected but no password provided'
)
pwd = read_repo_password('Zip is password protected. Please enter the password')
try:
zip_file.read(namelist[0], pwd=pwd.encode('utf-8'))
except RuntimeError as e:
raise InvalidZipRepository(
'Invalid password provided for protected repository'
) from e
# Find base directory
if namelist[0].endswith('/'):
base_dir = namelist[0]
else:
base_dir = os.path.commonprefix(namelist).rstrip('/')
if not base_dir:
raise InvalidZipRepository(
'CookieCutter templates must have a top level directory'
)
# Extract files
try:
> zip_file.extractall(temp_dir, pwd=pwd.encode('utf-8') if pwd else None)
cookiecutter/zipfile.py:106:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.10/zipfile.py:1660: in extractall
self._extract_member(zipinfo, path, pwd)
/usr/lib/python3.10/zipfile.py:1713: in _extract_member
with self.open(member, pwd=pwd) as source, \
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
name =
mode = 'r', pwd = None
def open(self, name, mode="r", pwd=None, *, force_zip64=False):
"""Return file-like object for 'name'.
name is a string for the file name within the ZIP file, or a ZipInfo
object.
mode should be 'r' to read a file already in the ZIP file, or 'w' to
write to a file newly added to the archive.
pwd is the password to decrypt files (only used for reading).
When writing, if the file size is not known in advance but may exceed
2 GiB, pass force_zip64 to use the ZIP64 format, which can handle large
files. If the size is known in advance, it is best to pass a ZipInfo
instance for name, with zinfo.file_size set.
"""
if mode not in {"r", "w"}:
raise ValueError('open() requires mode "r" or "w"')
if pwd and not isinstance(pwd, bytes):
raise TypeError("pwd: expected bytes, got %s" % type(pwd).__name__)
if pwd and (mode == "w"):
raise ValueError("pwd is only supported for reading files")
if not self.fp:
raise ValueError(
"Attempt to use ZIP archive that was already closed")
# Make sure we have an info object
if isinstance(name, ZipInfo):
# 'name' is already an info object
zinfo = name
elif mode == 'w':
zinfo = ZipInfo(name)
zinfo.compress_type = self.compression
zinfo._compresslevel = self.compresslevel
else:
# Get info object for name
zinfo = self.getinfo(name)
if mode == 'w':
return self._open_to_write(zinfo, force_zip64=force_zip64)
if self._writing:
raise ValueError("Can't read from the ZIP file while there "
"is an open writing handle on it. "
"Close the writing handle before trying to read.")
# Open for reading:
self._fileRefCnt += 1
zef_file = _SharedFile(self.fp, zinfo.header_offset,
self._fpclose, self._lock, lambda: self._writing)
try:
# Skip the file header:
fheader = zef_file.read(sizeFileHeader)
if len(fheader) != sizeFileHeader:
raise BadZipFile("Truncated file header")
fheader = struct.unpack(structFileHeader, fheader)
if fheader[_FH_SIGNATURE] != stringFileHeader:
raise BadZipFile("Bad magic number for file header")
fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
if fheader[_FH_EXTRA_FIELD_LENGTH]:
zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
if zinfo.flag_bits & 0x20:
# Zip 2.7: compressed patched data
raise NotImplementedError("compressed patched data (flag bit 5)")
if zinfo.flag_bits & 0x40:
# strong encryption
raise NotImplementedError("strong encryption (flag bit 6)")
if fheader[_FH_GENERAL_PURPOSE_FLAG_BITS] & 0x800:
# UTF-8 filename
fname_str = fname.decode("utf-8")
else:
fname_str = fname.decode("cp437")
if fname_str != zinfo.orig_filename:
raise BadZipFile(
'File name in directory %r and header %r differ.'
% (zinfo.orig_filename, fname))
if (zinfo._end_offset is not None and
zef_file.tell() + zinfo.compress_size > zinfo._end_offset):
raise BadZipFile(f"Overlapped entries: {zinfo.orig_filename!r} (possible zip bomb)")
# check for encrypted flag & handle password
is_encrypted = zinfo.flag_bits & 0x1
if is_encrypted:
if not pwd:
pwd = self.pwd
if not pwd:
> raise RuntimeError("File %r is encrypted, password "
"required for extraction" % name)
E RuntimeError: File is encrypted, password required for extraction
/usr/lib/python3.10/zipfile.py:1581: RuntimeError
The above exception was the direct cause of the following exception:
mocker =
clone_dir = PosixPath('/tmp/pytest-of-root/pytest-0/test_unzip_protected_local_fil3/clone_dir')
def test_unzip_protected_local_file_user_password(mocker, clone_dir):
"""A password-protected local file reference can be unzipped."""
mock_prompt_and_delete = mocker.patch(
'cookiecutter.zipfile.prompt_and_delete', return_value=True, autospec=True
)
mocker.patch('cookiecutter.zipfile.read_repo_password', return_value='sekrit')
> output_dir = zipfile.unzip(
'tests/files/protected-fake-repo-tmpl.zip',
is_url=False,
clone_to_dir=str(clone_dir),
)
tests/zipfile/test_unzip.py:100:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
zip_uri = 'tests/files/protected-fake-repo-tmpl.zip', is_url = False
clone_to_dir = '/tmp/pytest-of-root/pytest-0/test_unzip_protected_local_fil3/clone_dir'
no_input = False, password = None
def unzip(zip_uri: str, is_url: bool, clone_to_dir: 'os.PathLike[str]'='.', no_input: bool=False, password: Optional[str]=None):
"""Download and unpack a zipfile at a given URI.
This will download the zipfile to the cookiecutter repository,
and unpack into a temporary directory.
:param zip_uri: The URI for the zipfile.
:param is_url: Is the zip URI a URL or a file?
:param clone_to_dir: The cookiecutter repository directory
to put the archive into.
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:param password: The password to use when unpacking the repository.
:raises: InvalidZipRepository if the zip file is not a valid cookiecutter template.
:returns: The path to the unpacked template.
"""
# Ensure clone_to_dir exists
clone_to_dir = os.path.expanduser(clone_to_dir)
clone_to_dir = os.path.normpath(clone_to_dir)
make_sure_path_exists(clone_to_dir)
if is_url:
# Build cache path and download if needed
zip_path = os.path.join(clone_to_dir, os.path.basename(zip_uri))
if os.path.exists(zip_path):
if no_input:
os.remove(zip_path)
else:
download = prompt_and_delete(zip_path)
if not download:
return zip_path
# Download the zip file
response = requests.get(zip_uri, stream=True)
response.raise_for_status()
with open(zip_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
else:
zip_path = os.path.abspath(zip_uri)
if not os.path.exists(zip_path):
raise InvalidZipRepository(
f'Zip file {zip_path} does not exist'
)
# Create a temporary directory for the unzipped contents
temp_dir = tempfile.mkdtemp(prefix='cookiecutter-', suffix='-unzip')
try:
# Get password if needed but not provided
pwd = password
if pwd is None:
pwd = os.environ.get('COOKIECUTTER_REPO_PASSWORD')
with ZipFile(zip_path) as zip_file:
# Check if zip file is empty
namelist = zip_file.namelist()
if not namelist:
raise InvalidZipRepository(
'Zip file is empty'
)
# Check if password protected
try:
# Try to read first file to check if password is needed
zip_file.read(namelist[0], pwd=pwd.encode('utf-8') if pwd else None)
except RuntimeError:
if no_input:
raise InvalidZipRepository(
'Zip file is password protected but no password provided'
)
pwd = read_repo_password('Zip is password protected. Please enter the password')
try:
zip_file.read(namelist[0], pwd=pwd.encode('utf-8'))
except RuntimeError as e:
raise InvalidZipRepository(
'Invalid password provided for protected repository'
) from e
# Find base directory
if namelist[0].endswith('/'):
base_dir = namelist[0]
else:
base_dir = os.path.commonprefix(namelist).rstrip('/')
if not base_dir:
raise InvalidZipRepository(
'CookieCutter templates must have a top level directory'
)
# Extract files
try:
zip_file.extractall(temp_dir, pwd=pwd.encode('utf-8') if pwd else None)
except (RuntimeError, BadZipFile) as e:
> raise InvalidZipRepository(
'Unable to extract zip file contents'
) from e
E cookiecutter.exceptions.InvalidZipRepository: Unable to extract zip file contents
cookiecutter/zipfile.py:108: InvalidZipRepository
Patch diff
diff --git a/cookiecutter/cli.py b/cookiecutter/cli.py
index aed7f8f..acaa98e 100644
--- a/cookiecutter/cli.py
+++ b/cookiecutter/cli.py
@@ -12,15 +12,40 @@ from cookiecutter.main import cookiecutter
def version_msg():
"""Return the Cookiecutter version, location and Python powering it."""
- pass
+ python_version = sys.version[:3]
+ location = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ return f'Cookiecutter {__version__} from {location} (Python {python_version})'
def validate_extra_context(ctx, param, value):
"""Validate extra context."""
- pass
+ for s in value:
+ if '=' not in s:
+ raise click.BadParameter(
+ 'EXTRA_CONTEXT should contain items of the form key=value'
+ )
+
+ # Convert tuple -- e.g.: ('program_name=foobar', 'startsecs=66')
+ # to dict -- e.g.: {'program_name': 'foobar', 'startsecs': '66'}
+ return collections.OrderedDict(s.split('=', 1) for s in value) or None
def list_installed_templates(default_config, passed_config_file):
"""List installed (locally cloned) templates. Use cookiecutter --list-installed."""
- pass
+ config = get_user_config(default_config=default_config, passed_config_file=passed_config_file)
+
+ template_dir = config.get('cookiecutters_dir')
+ if not os.path.exists(template_dir):
+ click.echo(f'Error: Cannot list installed templates. Template dir {template_dir} does not exist.')
+ sys.exit(1)
+
+ template_names = [d for d in os.listdir(template_dir) if not d.startswith('.')]
+ if not template_names:
+ click.echo('No installed templates found.')
+ sys.exit(0)
+
+ click.echo('Installed templates:')
+ for template_name in template_names:
+ click.echo(f' {template_name}')
+ sys.exit(0)
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.version_option(__version__, '-V', '--version', message=version_msg())
@@ -48,6 +73,54 @@ def main(template, extra_context, no_input, checkout, verbose, replay, overwrite
volunteers. If you would like to help out or fund the project, please get
in touch at https://github.com/cookiecutter/cookiecutter.
"""
- pass
+ # Configure logging
+ configure_logger(
+ stream_level='DEBUG' if verbose else 'INFO',
+ debug_file=debug_file,
+ )
+
+ # List installed templates and exit
+ if list_installed:
+ list_installed_templates(default_config, config_file)
+
+ # Exit if no template is provided
+ if not template and not list_installed:
+ click.echo('Error: Missing argument "TEMPLATE".')
+ sys.exit(1)
+
+ # Input validation
+ if replay and no_input:
+ click.echo('Error: --no-input and --replay cannot be used together.')
+ sys.exit(1)
+
+ if replay and extra_context:
+ click.echo('Error: --replay and extra context cannot be used together.')
+ sys.exit(1)
+
+ # Run cookiecutter
+ try:
+ cookiecutter(
+ template,
+ checkout=checkout,
+ no_input=no_input,
+ extra_context=extra_context,
+ replay=replay,
+ overwrite_if_exists=overwrite_if_exists,
+ output_dir=output_dir,
+ config_file=config_file,
+ default_config=default_config,
+ password=None,
+ directory=directory,
+ skip_if_file_exists=skip_if_file_exists,
+ accept_hooks=accept_hooks == 'yes',
+ keep_project_on_failure=keep_project_on_failure,
+ replay_file=replay_file,
+ )
+ except (ContextDecodingException, OutputDirExistsException, InvalidModeException, FailedHookException, UnknownExtension, InvalidZipRepository, RepositoryNotFound, RepositoryCloneFailed) as e:
+ click.echo(f'Error: {e}')
+ sys.exit(1)
+ except UndefinedVariableInTemplate as undefined_err:
+ click.echo(f'{undefined_err.message} is undefined')
+ sys.exit(1)
if __name__ == '__main__':
main()
\ No newline at end of file
diff --git a/cookiecutter/environment.py b/cookiecutter/environment.py
index df924e7..ec3021d 100644
--- a/cookiecutter/environment.py
+++ b/cookiecutter/environment.py
@@ -32,7 +32,11 @@ class ExtensionLoaderMixin:
If context does not contain the relevant info, return an empty
list instead.
"""
- pass
+ try:
+ extensions = context['cookiecutter'].get('_extensions', [])
+ except KeyError:
+ extensions = []
+ return extensions
class StrictEnvironment(ExtensionLoaderMixin, Environment):
"""Create strict Jinja2 environment.
diff --git a/cookiecutter/find.py b/cookiecutter/find.py
index 0f5f351..dc294ea 100644
--- a/cookiecutter/find.py
+++ b/cookiecutter/find.py
@@ -10,6 +10,43 @@ def find_template(repo_dir: 'os.PathLike[str]', env: Environment) -> Path:
"""Determine which child directory of ``repo_dir`` is the project template.
:param repo_dir: Local directory of newly cloned repo.
+ :param env: Jinja2 environment for rendering template variables.
:return: Relative path to project template.
+ :raises: NonTemplatedInputDirException if no valid template directory is found.
"""
- pass
\ No newline at end of file
+ repo_dir = Path(repo_dir)
+ logger.debug('Searching %s for the project template.', repo_dir)
+
+ # Check for a cookiecutter.json file in the repo_dir
+ template_dir = repo_dir
+ if (template_dir / 'cookiecutter.json').exists():
+ return template_dir
+
+ # Check for a cookiecutter.json file in a _cookiecutter directory
+ template_dir = repo_dir / '_cookiecutter'
+ if (template_dir / 'cookiecutter.json').exists():
+ return template_dir
+
+ # Check for a cookiecutter.json file in a cookiecutter directory
+ template_dir = repo_dir / 'cookiecutter'
+ if (template_dir / 'cookiecutter.json').exists():
+ return template_dir
+
+ # Check for a cookiecutter.json file in any of the subdirectories
+ for dir_name in os.listdir(repo_dir):
+ dir_path = repo_dir / dir_name
+ if dir_path.is_dir() and not dir_name.startswith('.'):
+ # Try to render the directory name with Jinja2
+ try:
+ rendered_name = env.from_string(dir_name).render()
+ rendered_path = repo_dir / rendered_name
+ if (rendered_path / 'cookiecutter.json').exists():
+ return rendered_path
+ except Exception:
+ pass
+
+ # Try the original directory name
+ if (dir_path / 'cookiecutter.json').exists():
+ return dir_path
+
+ raise NonTemplatedInputDirException
\ No newline at end of file
diff --git a/cookiecutter/generate.py b/cookiecutter/generate.py
index f620d04..a86f971 100644
--- a/cookiecutter/generate.py
+++ b/cookiecutter/generate.py
@@ -26,11 +26,25 @@ def is_copy_only_path(path, context):
should be rendered or just copied.
:param context: cookiecutter context.
"""
- pass
+ try:
+ copy_without_render = context['cookiecutter'].get('_copy_without_render', [])
+ except KeyError:
+ return False
+
+ for pattern in copy_without_render:
+ if fnmatch.fnmatch(path, pattern):
+ return True
+ return False
def apply_overwrites_to_context(context, overwrite_context, *, in_dictionary_variable=False):
"""Modify the given context in place based on the overwrite_context."""
- pass
+ for key, value in overwrite_context.items():
+ if isinstance(value, dict):
+ if key not in context:
+ context[key] = {}
+ apply_overwrites_to_context(context[key], value, in_dictionary_variable=True)
+ else:
+ context[key] = value
def generate_context(context_file='cookiecutter.json', default_context=None, extra_context=None):
"""Generate the context for a Cookiecutter project template.
@@ -42,7 +56,28 @@ def generate_context(context_file='cookiecutter.json', default_context=None, ext
:param default_context: Dictionary containing config to take into account.
:param extra_context: Dictionary containing configuration overrides
"""
- pass
+ context = {}
+
+ try:
+ with open(context_file, encoding='utf-8') as file_handle:
+ obj = json.load(file_handle, object_pairs_hook=OrderedDict)
+ except ValueError as e:
+ raise ContextDecodingException(
+ f'JSON decoding error while loading "{context_file}". '
+ f'Error details: {str(e)}'
+ ) from e
+
+ context['cookiecutter'] = obj
+
+ # Apply defaults
+ if default_context:
+ apply_overwrites_to_context(context['cookiecutter'], default_context)
+
+ # Apply overrides
+ if extra_context:
+ apply_overwrites_to_context(context['cookiecutter'], extra_context)
+
+ return context
def generate_file(project_dir, infile, context, env, skip_if_file_exists=False):
"""Render filename of infile as name of outfile, handle infile correctly.
@@ -65,11 +100,71 @@ def generate_file(project_dir, infile, context, env, skip_if_file_exists=False):
:param context: Dict for populating the cookiecutter's variables.
:param env: Jinja2 template execution environment.
"""
- pass
+ logger.debug('Processing file %s', infile)
+
+ # Render the path to the output file (not the contents of the input file)
+ outfile_tmpl = env.from_string(infile)
+ outfile = outfile_tmpl.render(**context)
+ outfile_path = os.path.join(project_dir, outfile)
+
+ # Skip if file exists
+ if skip_if_file_exists and os.path.exists(outfile_path):
+ logger.debug('File %s already exists, skipping', outfile)
+ return []
+
+ # Create the parent directory if it doesn't exist
+ parent_dir = os.path.dirname(outfile_path)
+ if parent_dir and not os.path.exists(parent_dir):
+ make_sure_path_exists(parent_dir)
+
+ # Just copy over binary files without rendering
+ logger.debug("Check %s to see if it's a binary", infile)
+ if is_binary(infile) or is_copy_only_path(infile, context):
+ logger.debug('Copying binary %s to %s without rendering', infile, outfile)
+ shutil.copyfile(infile, outfile_path)
+ return [outfile_path]
+
+ # For text files, render the contents and write the rendered file
+ try:
+ with open(infile, encoding='utf-8') as f:
+ tmpl = env.from_string(f.read())
+ rendered_file = tmpl.render(**context)
+
+ logger.debug('Writing %s', outfile)
+ with open(outfile_path, 'w', encoding='utf-8') as fh:
+ fh.write(rendered_file)
+
+ except UndefinedError as err:
+ msg = f"Unable to create file '{outfile}': {err.message}"
+ raise UndefinedVariableInTemplate(msg, err.message, context, outfile) from err
+ except TemplateSyntaxError as err:
+ raise TemplateSyntaxError(
+ err.message,
+ err.lineno,
+ name=infile,
+ filename=infile,
+ ) from err
+
+ return [outfile_path]
def render_and_create_dir(dirname: str, context: dict, output_dir: 'os.PathLike[str]', environment: Environment, overwrite_if_exists: bool=False):
"""Render name of a directory, create the directory, return its path."""
- pass
+ name_tmpl = environment.from_string(dirname)
+ rendered_dirname = name_tmpl.render(**context)
+
+ dir_to_create = os.path.normpath(os.path.join(output_dir, rendered_dirname))
+
+ logger.debug('Rendered dir %s must exist in output_dir %s', dir_to_create, output_dir)
+
+ if os.path.exists(dir_to_create):
+ if overwrite_if_exists:
+ logger.debug('Removing existing directory %s', dir_to_create)
+ rmtree(dir_to_create)
+ else:
+ raise OutputDirExistsException(dir_to_create)
+
+ make_sure_path_exists(dir_to_create)
+ return dir_to_create
def _run_hook_from_repo_dir(repo_dir, hook_name, project_dir, context, delete_project_on_failure):
"""Run hook from repo directory, clean project directory if hook fails.
@@ -81,7 +176,22 @@ def _run_hook_from_repo_dir(repo_dir, hook_name, project_dir, context, delete_pr
:param delete_project_on_failure: Delete the project directory on hook
failure?
"""
- pass
+ with work_in(repo_dir):
+ try:
+ run_hook_from_repo_dir(
+ project_dir=project_dir,
+ hook_name=hook_name,
+ context=context
+ )
+ except Exception:
+ if delete_project_on_failure:
+ rmtree(project_dir)
+ logger.error(
+ "Stopping generation because %s hook "
+ "script didn't exit successfully",
+ hook_name
+ )
+ raise
def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=False, skip_if_file_exists=False, accept_hooks=True, keep_project_on_failure=False):
"""Render the templates and saves them to files.
@@ -97,4 +207,67 @@ def generate_files(repo_dir, context=None, output_dir='.', overwrite_if_exists=F
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
"""
- pass
\ No newline at end of file
+ context = context or {}
+ env = create_env_with_context(context)
+
+ template_dir = find_template(repo_dir)
+ logger.debug('Generating project from %s...', template_dir)
+
+ # Create project dir
+ project_dir = render_and_create_dir(
+ dirname=context['cookiecutter']['_template'],
+ context=context,
+ output_dir=output_dir,
+ environment=env,
+ overwrite_if_exists=overwrite_if_exists,
+ )
+
+ # We want the Jinja path and the OS paths to match. Consequently, we'll:
+ # 1. CD to the template folder
+ # 2. Walk through the folder and generate files
+ # 3. CD back to where we started
+ with work_in(template_dir):
+ if accept_hooks:
+ _run_hook_from_repo_dir(
+ repo_dir=repo_dir,
+ hook_name='pre_gen_project',
+ project_dir=project_dir,
+ context=context,
+ delete_project_on_failure=not keep_project_on_failure,
+ )
+
+ for root, dirs, files in os.walk('.'):
+ # Skip certain directories
+ for dirname in dirs[:]:
+ if dirname.startswith(('.', '_')):
+ dirs.remove(dirname)
+
+ # Handle files
+ for filename in files:
+ if filename.startswith(('.', '_')):
+ continue
+
+ infile = os.path.join(root, filename)
+ try:
+ generate_file(
+ project_dir=project_dir,
+ infile=infile,
+ context=context,
+ env=env,
+ skip_if_file_exists=skip_if_file_exists,
+ )
+ except UndefinedVariableInTemplate as err:
+ if not keep_project_on_failure:
+ rmtree(project_dir)
+ raise err
+
+ if accept_hooks:
+ _run_hook_from_repo_dir(
+ repo_dir=repo_dir,
+ hook_name='post_gen_project',
+ project_dir=project_dir,
+ context=context,
+ delete_project_on_failure=not keep_project_on_failure,
+ )
+
+ return project_dir
\ No newline at end of file
diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py
index 3438d86..ae87e55 100644
--- a/cookiecutter/hooks.py
+++ b/cookiecutter/hooks.py
@@ -21,7 +21,10 @@ def valid_hook(hook_file, hook_name):
:param hook_name: The hook to find
:return: The hook file validity
"""
- pass
+ filename = os.path.basename(hook_file)
+ basename = os.path.splitext(filename)[0]
+
+ return hook_name == basename and os.path.isfile(hook_file)
def find_hook(hook_name, hooks_dir='hooks'):
"""Return a dict of all hook scripts provided.
@@ -35,7 +38,24 @@ def find_hook(hook_name, hooks_dir='hooks'):
:param hooks_dir: The hook directory in the template
:return: The absolute path to the hook script or None
"""
- pass
+ if not os.path.exists(hooks_dir):
+ logger.debug('No hooks directory found')
+ return None
+
+ hook_dir_candidates = [hooks_dir]
+ if os.path.exists('cookiecutter.json'):
+ hook_dir_candidates.append(os.path.join(hooks_dir, hook_name))
+
+ for candidate in hook_dir_candidates:
+ if not os.path.exists(candidate):
+ continue
+
+ for hook_file in os.listdir(candidate):
+ hook_path = os.path.join(candidate, hook_file)
+ if valid_hook(hook_path, hook_name):
+ return os.path.abspath(hook_path)
+
+ return None
def run_script(script_path, cwd='.'):
"""Execute a script from a working directory.
@@ -43,7 +63,31 @@ def run_script(script_path, cwd='.'):
:param script_path: Absolute path to the script to run.
:param cwd: The directory to run the script from.
"""
- pass
+ run_thru_shell = sys.platform.startswith('win')
+ if script_path.endswith('.py'):
+ script_command = [sys.executable, script_path]
+ else:
+ script_command = [script_path]
+
+ try:
+ proc = subprocess.Popen(
+ script_command,
+ shell=run_thru_shell,
+ cwd=cwd
+ )
+ exit_status = proc.wait()
+ if exit_status != EXIT_SUCCESS:
+ raise FailedHookException(
+ f'Hook script failed (exit status: {exit_status})'
+ )
+ except OSError as os_error:
+ if os_error.errno == errno.ENOEXEC:
+ raise FailedHookException(
+ 'Hook script failed, might be an empty or invalid script file'
+ )
+ raise FailedHookException(
+ 'Hook script failed (error: {})'.format(os_error)
+ )
def run_script_with_context(script_path, cwd, context):
"""Execute a script after rendering it with Jinja.
@@ -52,7 +96,33 @@ def run_script_with_context(script_path, cwd, context):
:param cwd: The directory to run the script from.
:param context: Cookiecutter project template context.
"""
- pass
+ _, extension = os.path.splitext(script_path)
+
+ with open(script_path, 'r', encoding='utf-8') as f:
+ contents = f.read()
+
+ try:
+ env = create_env_with_context(context)
+ script_contents = env.from_string(contents).render(**context)
+ except UndefinedError as err:
+ msg = f"Unable to render hook script '{script_path}': {err.message}"
+ raise UndefinedError(msg)
+
+ # Write rendered script to temp file
+ temp_dir = create_tmp_repo_dir()
+ temp_script = os.path.join(temp_dir, f'hook{extension}')
+
+ with open(temp_script, 'w', encoding='utf-8') as f:
+ f.write(script_contents)
+
+ # Set appropriate mode
+ mode = os.stat(script_path).st_mode
+ os.chmod(temp_script, mode)
+
+ try:
+ run_script(temp_script, cwd)
+ finally:
+ rmtree(temp_dir)
def run_hook(hook_name, project_dir, context):
"""
@@ -62,7 +132,10 @@ def run_hook(hook_name, project_dir, context):
:param project_dir: The directory to execute the script from.
:param context: Cookiecutter project context.
"""
- pass
+ with work_in(project_dir):
+ hook_path = find_hook(hook_name)
+ if hook_path:
+ run_script_with_context(hook_path, project_dir, context)
def run_hook_from_repo_dir(repo_dir, hook_name, project_dir, context, delete_project_on_failure):
"""Run hook from repo directory, clean project directory if hook fails.
@@ -74,11 +147,34 @@ def run_hook_from_repo_dir(repo_dir, hook_name, project_dir, context, delete_pro
:param delete_project_on_failure: Delete the project directory on hook
failure?
"""
- pass
+ with work_in(repo_dir):
+ try:
+ run_hook(hook_name, project_dir, context)
+ except Exception:
+ if delete_project_on_failure:
+ rmtree(project_dir)
+ logger.error(
+ "Stopping generation because %s hook "
+ "script didn't exit successfully",
+ hook_name
+ )
+ raise
def run_pre_prompt_hook(repo_dir: 'os.PathLike[str]') -> Path:
"""Run pre_prompt hook from repo directory.
:param repo_dir: Project template input directory.
"""
- pass
\ No newline at end of file
+ # Create a temporary directory for the pre-prompt hook
+ temp_dir = create_tmp_repo_dir()
+
+ try:
+ with work_in(repo_dir):
+ hook_path = find_hook('pre_prompt')
+ if hook_path:
+ run_script(hook_path, temp_dir)
+ except Exception:
+ rmtree(temp_dir)
+ raise
+
+ return Path(temp_dir)
\ No newline at end of file
diff --git a/cookiecutter/main.py b/cookiecutter/main.py
index 6a60f45..04353ef 100644
--- a/cookiecutter/main.py
+++ b/cookiecutter/main.py
@@ -46,8 +46,72 @@ def cookiecutter(template, checkout=None, no_input=False, extra_context=None, re
:param accept_hooks: Accept pre and post hooks if set to `True`.
:param keep_project_on_failure: If `True` keep generated project directory even when
generation fails
+ :raises: `InvalidModeException` if both `no_input` and `replay` are True.
"""
- pass
+ if replay and no_input:
+ raise InvalidModeException(
+ 'You cannot use both replay and no_input flags at the same time.'
+ )
+
+ # Get user config from ~/.cookiecutterrc or equivalent
+ config_dict = get_user_config(
+ config_file=config_file,
+ default_config=default_config,
+ )
+
+ # Get the repo dir, where the cookiecutter template source is stored
+ repo_dir, cleanup = determine_repo_dir(
+ template=template,
+ abbreviations=config_dict['abbreviations'],
+ clone_to_dir=config_dict['cookiecutters_dir'],
+ checkout=checkout,
+ no_input=no_input,
+ password=password,
+ directory=directory
+ )
+
+ # Run pre-prompt hook if it exists
+ if accept_hooks:
+ with _patch_import_path_for_repo(repo_dir):
+ run_pre_prompt_hook(repo_dir)
+
+ # Determine context dict for rendering template
+ if replay:
+ context = load(config_dict['replay_dir'], template)
+ else:
+ # First generate context from json file defaults
+ context = generate_context(
+ context_file=os.path.join(repo_dir, 'cookiecutter.json'),
+ default_context=config_dict['default_context'],
+ extra_context=extra_context,
+ )
+
+ # If not using replay, prompt user for values
+ if not no_input:
+ context = prompt_for_config(context)
+
+ # Include any nested templates
+ context = choose_nested_template(context, repo_dir)
+
+ # Save context for later replay
+ dump(config_dict['replay_dir'], template, context)
+
+ # Create project from local context and project template.
+ result = generate_files(
+ repo_dir=repo_dir,
+ context=context,
+ overwrite_if_exists=overwrite_if_exists,
+ skip_if_file_exists=skip_if_file_exists,
+ output_dir=output_dir,
+ accept_hooks=accept_hooks,
+ keep_project_on_failure=keep_project_on_failure,
+ )
+
+ # Cleanup (if required)
+ if cleanup:
+ rmtree(repo_dir)
+
+ return result
class _patch_import_path_for_repo:
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
index cf327dd..6f6011b 100644
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -15,8 +15,15 @@ def read_user_variable(var_name, default_value, prompts=None, prefix=''):
:param str var_name: Variable of the context to query the user
:param default_value: Value that will be returned if no input happens
+ :param prompts: Optional dict with custom prompts for variables
+ :param prefix: Optional prefix to use for variable prompts
+ :returns: User's input or default value
"""
- pass
+ if prompts is None:
+ prompts = {}
+
+ prompt_text = prompts.get(var_name, f'{prefix}{var_name}')
+ return Prompt.ask(prompt_text, default=default_value)
class YesNoPrompt(Confirm):
"""A prompt that returns a boolean for yes/no questions."""
@@ -25,7 +32,12 @@ class YesNoPrompt(Confirm):
def process_response(self, value: str) -> bool:
"""Convert choices to a bool."""
- pass
+ value = value.lower()
+ if value in self.yes_choices:
+ return True
+ if value in self.no_choices:
+ return False
+ raise InvalidResponse(self.validate_error_message)
def read_user_yes_no(var_name, default_value, prompts=None, prefix=''):
"""Prompt the user to reply with 'yes' or 'no' (or equivalent values).
@@ -35,20 +47,25 @@ def read_user_yes_no(var_name, default_value, prompts=None, prefix=''):
- These input values will be converted to ``False``:
"0", "false", "f", "no", "n", "off"
- Actual parsing done by :func:`prompt`; Check this function codebase change in
- case of unexpected behaviour.
-
- :param str question: Question to the user
+ :param str var_name: Variable as specified in the context
:param default_value: Value that will be returned if no input happens
+ :param prompts: Optional dict with custom prompts for variables
+ :param prefix: Optional prefix to use for variable prompts
+ :returns: User's boolean choice
"""
- pass
+ if prompts is None:
+ prompts = {}
+
+ prompt_text = prompts.get(var_name, f'{prefix}{var_name}')
+ return YesNoPrompt.ask(prompt_text, default=default_value)
def read_repo_password(question):
"""Prompt the user to enter a password.
:param str question: Question to the user
+ :returns: The entered password
"""
- pass
+ return Prompt.ask(question, password=True)
def read_user_choice(var_name, options, prompts=None, prefix=''):
"""Prompt the user to choose from several options for the given variable.
@@ -57,17 +74,41 @@ def read_user_choice(var_name, options, prompts=None, prefix=''):
:param str var_name: Variable as specified in the context
:param list options: Sequence of options that are available to select from
+ :param prompts: Optional dict with custom prompts for variables
+ :param prefix: Optional prefix to use for variable prompts
:return: Exactly one item of ``options`` that has been chosen by the user
"""
- pass
+ if not options:
+ raise ValueError('Options list must not be empty')
+
+ if prompts is None:
+ prompts = {}
+
+ prompt_text = prompts.get(var_name, f'{prefix}{var_name}')
+ choices = [str(i) for i in range(len(options))]
+ choice_map = dict(zip(choices, options))
+
+ choice_lines = [f'{i}) {opt}' for i, opt in enumerate(options)]
+ choice_text = '\n'.join(choice_lines)
+ prompt_text = f'{prompt_text}\n{choice_text}\nChoose from {min(choices)} to {max(choices)}'
+
+ choice = Prompt.ask(prompt_text, choices=choices, default='0')
+ return choice_map[choice]
+
DEFAULT_DISPLAY = 'default'
def process_json(user_value, default_value=None):
"""Load user-supplied value as a JSON dict.
:param str user_value: User-supplied value to load as a JSON dict
+ :param default_value: Value to return if parsing fails
+ :returns: The parsed JSON dict or default value
"""
- pass
+ try:
+ user_dict = json.loads(user_value, object_pairs_hook=OrderedDict)
+ return user_dict
+ except Exception:
+ return default_value
class JsonPrompt(PromptBase[dict]):
"""A prompt that returns a dict from JSON string."""
@@ -77,16 +118,25 @@ class JsonPrompt(PromptBase[dict]):
def process_response(self, value: str) -> dict:
"""Convert choices to a dict."""
- pass
+ try:
+ return json.loads(value, object_pairs_hook=OrderedDict)
+ except Exception:
+ raise InvalidResponse(self.validate_error_message)
def read_user_dict(var_name, default_value, prompts=None, prefix=''):
"""Prompt the user to provide a dictionary of data.
:param str var_name: Variable as specified in the context
:param default_value: Value that will be returned if no input is provided
+ :param prompts: Optional dict with custom prompts for variables
+ :param prefix: Optional prefix to use for variable prompts
:return: A Python dictionary to use in the context.
"""
- pass
+ if prompts is None:
+ prompts = {}
+
+ prompt_text = prompts.get(var_name, f'{prefix}{var_name}')
+ return JsonPrompt.ask(prompt_text, default=json.dumps(default_value))
def render_variable(env, raw, cookiecutter_dict):
"""Render the next variable to be displayed in the user prompt.
@@ -105,33 +155,118 @@ def render_variable(env, raw, cookiecutter_dict):
being populated with variables.
:return: The rendered value for the default variable.
"""
- pass
+ if not isinstance(raw, str):
+ return raw
+
+ template = env.from_string(raw)
+ rendered = template.render(**cookiecutter_dict)
+
+ return rendered
def _prompts_from_options(options: dict) -> dict:
"""Process template options and return friendly prompt information."""
- pass
+ prompts = {}
+ for key, raw in options.items():
+ if not isinstance(raw, dict):
+ continue
+
+ display = raw.get('_display', DEFAULT_DISPLAY)
+ if not isinstance(display, str):
+ continue
+
+ prompts[key] = display
+
+ return prompts
def prompt_choice_for_template(key, options, no_input):
"""Prompt user with a set of options to choose from.
+ :param key: Key name for the choice
+ :param options: Available choices
:param no_input: Do not prompt for user input and return the first available option.
+ :returns: The selected choice
"""
- pass
+ if no_input:
+ return next(iter(options.values()))
+
+ choices = []
+ display = []
+ for opt_key, opt_val in options.items():
+ choices.append(opt_key)
+ if isinstance(opt_val, dict):
+ opt_display = opt_val.get('_display', DEFAULT_DISPLAY)
+ display.append(f'{opt_key} - {opt_display}')
+ else:
+ display.append(opt_key)
+
+ prompt_text = f'{key}\n' + '\n'.join(display)
+ choice = Prompt.ask(prompt_text, choices=choices, default=choices[0])
+ return options[choice]
def prompt_choice_for_config(cookiecutter_dict, env, key, options, no_input, prompts=None, prefix=''):
"""Prompt user with a set of options to choose from.
+ :param cookiecutter_dict: Dict to use for rendering options
+ :param env: Jinja2 Environment for rendering
+ :param key: Key name for the choice
+ :param options: Available choices
:param no_input: Do not prompt for user input and return the first available option.
+ :param prompts: Optional dict with custom prompts for variables
+ :param prefix: Optional prefix to use for variable prompts
+ :returns: The selected choice
"""
- pass
+ rendered_options = [render_variable(env, opt, cookiecutter_dict) for opt in options]
+ return read_user_choice(key, rendered_options, prompts=prompts, prefix=prefix)
def prompt_for_config(context, no_input=False):
"""Prompt user to enter a new config.
:param dict context: Source for field names and sample values.
:param no_input: Do not prompt for user input and use only values from context.
+ :returns: A new config dict with user's responses
"""
- pass
+ cookiecutter_dict = context['cookiecutter']
+ env = create_env_with_context(context)
+ prompts = _prompts_from_options(cookiecutter_dict)
+
+ for key, raw in cookiecutter_dict.items():
+ if key.startswith('_'):
+ cookiecutter_dict[key] = raw
+ continue
+
+ try:
+ if isinstance(raw, list):
+ # Choice field
+ val = prompt_choice_for_config(
+ cookiecutter_dict, env, key, raw,
+ no_input, prompts
+ )
+ elif isinstance(raw, bool):
+ # Boolean field
+ val = read_user_yes_no(
+ key, raw,
+ prompts=prompts
+ ) if not no_input else raw
+ elif isinstance(raw, dict):
+ # Dict field
+ val = read_user_dict(
+ key, raw,
+ prompts=prompts
+ ) if not no_input else raw
+ else:
+ # String field
+ val = render_variable(env, raw, cookiecutter_dict)
+ if not no_input:
+ val = read_user_variable(
+ key, val,
+ prompts=prompts
+ )
+ cookiecutter_dict[key] = val
+ except UndefinedError as err:
+ msg = f"Unable to render variable '{key}': {err.message}"
+ raise UndefinedVariableInTemplate(msg, err.message, context, key)
+
+ return context
def choose_nested_template(context: dict, repo_dir: str, no_input: bool=False) -> str:
"""Prompt user to select the nested template to use.
@@ -141,7 +276,20 @@ def choose_nested_template(context: dict, repo_dir: str, no_input: bool=False) -
:param no_input: Do not prompt for user input and use only values from context.
:returns: Path to the selected template.
"""
- pass
+ cookiecutter_dict = context['cookiecutter']
+ if '_template' not in cookiecutter_dict:
+ return context
+
+ template_dir = cookiecutter_dict['_template']
+ if not isinstance(template_dir, dict):
+ return context
+
+ template_path = prompt_choice_for_template('_template', template_dir, no_input)
+ if not isinstance(template_path, str):
+ return context
+
+ cookiecutter_dict['_template'] = template_path
+ return context
def prompt_and_delete(path, no_input=False):
"""
@@ -154,4 +302,25 @@ def prompt_and_delete(path, no_input=False):
:param no_input: Suppress prompt to delete repo and just delete it.
:return: True if the content was deleted
"""
- pass
\ No newline at end of file
+ if no_input:
+ rmtree(path)
+ return True
+
+ ok_to_delete = YesNoPrompt.ask(
+ f'You have downloaded {path} before. Is it okay to delete and re-download it?',
+ default=True
+ )
+
+ if ok_to_delete:
+ rmtree(path)
+ return True
+
+ ok_to_reuse = YesNoPrompt.ask(
+ 'Do you want to re-use the existing version?',
+ default=True
+ )
+
+ if ok_to_reuse:
+ return False
+
+ sys.exit()
\ No newline at end of file
diff --git a/cookiecutter/replay.py b/cookiecutter/replay.py
index 267022b..a572c0c 100644
--- a/cookiecutter/replay.py
+++ b/cookiecutter/replay.py
@@ -8,13 +8,62 @@ import os
from cookiecutter.utils import make_sure_path_exists
def get_file_name(replay_dir, template_name):
- """Get the name of file."""
- pass
+ """Get the name of file.
+
+ :param replay_dir: Directory where the replay file will be written.
+ :param template_name: Name of the template.
+ :returns: Name of the file.
+ """
+ file_name = template_name.split('/')[-1]
+ if not file_name.endswith('.json'):
+ file_name = f'{file_name}.json'
+ return os.path.join(replay_dir, file_name)
def dump(replay_dir: 'os.PathLike[str]', template_name: str, context: dict):
- """Write json data to file."""
- pass
+ """Write json data to file.
+
+ :param replay_dir: Directory where the replay file will be written.
+ :param template_name: Name of the template.
+ :param context: Context dictionary to be dumped.
+ :raises: TypeError if template_name is not a string
+ TypeError if context is not a dict
+ ValueError if context is empty
+ OSError if replay_dir cannot be created
+ """
+ if not isinstance(template_name, str):
+ raise TypeError('Template name is required to be of type str')
+ if not isinstance(context, dict):
+ raise TypeError('Context is required to be of type dict')
+ if not context:
+ raise ValueError('Context is required to not be empty')
+
+ make_sure_path_exists(replay_dir)
+
+ replay_file = get_file_name(replay_dir, template_name)
+ with open(replay_file, 'w', encoding='utf-8') as f:
+ json.dump(context, f, indent=2)
def load(replay_dir, template_name):
- """Read json data from file."""
- pass
\ No newline at end of file
+ """Read json data from file.
+
+ :param replay_dir: Directory where the replay file is located.
+ :param template_name: Name of the template.
+ :raises: TypeError if template_name is not a string
+ ValueError if context is empty
+ IOError if replay file does not exist
+ :returns: Context dictionary from the replay file.
+ """
+ if not isinstance(template_name, str):
+ raise TypeError('Template name is required to be of type str')
+
+ replay_file = get_file_name(replay_dir, template_name)
+ if not os.path.exists(replay_file):
+ raise IOError(f'No replay file found at {replay_file}')
+
+ with open(replay_file, encoding='utf-8') as f:
+ context = json.load(f)
+
+ if not context:
+ raise ValueError('Context is required to not be empty')
+
+ return context
\ No newline at end of file
diff --git a/cookiecutter/repository.py b/cookiecutter/repository.py
index 6ae286e..e65cce8 100644
--- a/cookiecutter/repository.py
+++ b/cookiecutter/repository.py
@@ -4,15 +4,20 @@ import re
from cookiecutter.exceptions import RepositoryNotFound
from cookiecutter.vcs import clone
from cookiecutter.zipfile import unzip
-REPO_REGEX = re.compile('\n# something like git:// ssh:// file:// etc.\n((((git|hg)\\+)?(git|ssh|file|https?):(//)?)\n | # or\n (\\w+@[\\w\\.]+) # something like user@...\n)\n', re.VERBOSE)
+REPO_REGEX = re.compile(r'''
+# something like git:// ssh:// file:// etc.
+((((git|hg)\+)?(git|ssh|file|https?):(//)?)|
+# or
+(\w+@[\w\.]+))
+''', re.VERBOSE)
def is_repo_url(value):
"""Return True if value is a repository URL."""
- pass
+ return bool(REPO_REGEX.match(value))
def is_zip_file(value):
"""Return True if value is a zip file."""
- pass
+ return value.endswith('.zip') or value.endswith('.gz') or value.endswith('.tar')
def expand_abbreviations(template, abbreviations):
"""Expand abbreviations in a template name.
@@ -20,7 +25,18 @@ def expand_abbreviations(template, abbreviations):
:param template: The project template name.
:param abbreviations: Abbreviation definitions.
"""
- pass
+ # Split on colon only if it is not preceded by a backslash
+ pattern = re.compile(r'(?<!\\):')
+ parts = pattern.split(template)
+
+ if len(parts) > 1 and parts[0] in abbreviations:
+ template = abbreviations[parts[0]]
+ if len(parts) > 2:
+ template = template.format(*parts[1:])
+ else:
+ template = template.format(parts[1])
+
+ return template
def repository_has_cookiecutter_json(repo_directory):
"""Determine if `repo_directory` contains a `cookiecutter.json` file.
@@ -28,7 +44,9 @@ def repository_has_cookiecutter_json(repo_directory):
:param repo_directory: The candidate repository directory.
:return: True if the `repo_directory` is valid, else False.
"""
- pass
+ repo_directory_exists = os.path.isdir(repo_directory)
+ repo_config_exists = os.path.isfile(os.path.join(repo_directory, 'cookiecutter.json'))
+ return repo_directory_exists and repo_config_exists
def determine_repo_dir(template, abbreviations, clone_to_dir, checkout, no_input, password=None, directory=None):
"""
@@ -53,4 +71,54 @@ def determine_repo_dir(template, abbreviations, clone_to_dir, checkout, no_input
after the template has been instantiated.
:raises: `RepositoryNotFound` if a repository directory could not be found.
"""
- pass
\ No newline at end of file
+ # Expand abbreviations in template name
+ template = expand_abbreviations(template, abbreviations)
+
+ # If it's a local repo, no need to clone or copy
+ if os.path.isdir(template):
+ repository_candidates = [template]
+ if directory:
+ repository_candidates.append(os.path.join(template, directory))
+ for repository_candidate in repository_candidates:
+ if repository_has_cookiecutter_json(repository_candidate):
+ return repository_candidate, False
+
+ # If it's a URL and ends with .zip, download and unpack it
+ if is_zip_file(template):
+ downloaded_repo_dir = unzip(
+ zip_uri=template,
+ is_url=is_repo_url(template),
+ clone_to_dir=clone_to_dir,
+ no_input=no_input,
+ password=password
+ )
+ repository_candidates = [downloaded_repo_dir]
+ if directory:
+ repository_candidates.append(os.path.join(downloaded_repo_dir, directory))
+ for repository_candidate in repository_candidates:
+ if repository_has_cookiecutter_json(repository_candidate):
+ return repository_candidate, True
+
+ # Otherwise, assume it's a git or mercurial repo URL
+ repo_dir = clone(
+ repo_url=template,
+ checkout=checkout,
+ clone_to_dir=clone_to_dir,
+ no_input=no_input
+ )
+
+ repository_candidates = [repo_dir]
+ if directory:
+ repository_candidates.append(os.path.join(repo_dir, directory))
+
+ for repository_candidate in repository_candidates:
+ if repository_has_cookiecutter_json(repository_candidate):
+ return repository_candidate, True
+
+ raise RepositoryNotFound(
+ 'A valid repository for "{}" could not be found in the following '
+ 'locations:\n{}'.format(
+ template,
+ '\n'.join(repository_candidates)
+ )
+ )
\ No newline at end of file
diff --git a/cookiecutter/vcs.py b/cookiecutter/vcs.py
index 9cfc59a..7f046e9 100644
--- a/cookiecutter/vcs.py
+++ b/cookiecutter/vcs.py
@@ -18,16 +18,36 @@ def identify_repo(repo_url):
:param repo_url: Repo URL of unknown type.
:returns: ('git', repo_url), ('hg', repo_url), or None.
+ :raises: UnknownRepoType if the repo type cannot be determined.
"""
- pass
+ if repo_url.startswith('git+'):
+ return 'git', repo_url[4:]
+ elif repo_url.startswith('hg+'):
+ return 'hg', repo_url[3:]
+ elif any(host in repo_url for host in ['github.com', 'gitlab.com', 'gitorious.org']):
+ return 'git', repo_url
+ elif 'bitbucket.org' in repo_url:
+ if repo_url.endswith('.git'):
+ return 'git', repo_url
+ else:
+ return 'hg', repo_url
+ elif repo_url.endswith('.git'):
+ return 'git', repo_url
+ elif repo_url.endswith('.hg'):
+ return 'hg', repo_url
+ elif '@' in repo_url and ':' in repo_url:
+ # SSH URL format: [user@]host:path
+ return 'git', repo_url
+ raise UnknownRepoType
def is_vcs_installed(repo_type):
"""
Check if the version control system for a repo type is installed.
- :param repo_type:
+ :param repo_type: Name of the version control system to check.
+ :returns: True if VCS executable is found, False otherwise.
"""
- pass
+ return bool(which(repo_type))
def clone(repo_url: str, checkout: Optional[str]=None, clone_to_dir: 'os.PathLike[str]'='.', no_input: bool=False):
"""Clone a repo to the current directory.
@@ -39,5 +59,91 @@ def clone(repo_url: str, checkout: Optional[str]=None, clone_to_dir: 'os.PathLik
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:returns: str with path to the new directory of the repository.
+ :raises: VCSNotInstalled if the required VCS is not installed
+ RepositoryNotFound if the repository cannot be found
+ RepositoryCloneFailed if the repository cannot be cloned
"""
- pass
\ No newline at end of file
+ # Ensure clone_to_dir exists
+ clone_to_dir = os.path.expanduser(clone_to_dir)
+ clone_to_dir = os.path.normpath(clone_to_dir)
+ make_sure_path_exists(clone_to_dir)
+
+ # Get repo type and url
+ repo_type, repo_url = identify_repo(repo_url)
+
+ # Check if VCS is installed
+ if not is_vcs_installed(repo_type):
+ raise VCSNotInstalled(f'{repo_type} is not installed.')
+
+ repo_url = repo_url.rstrip('/')
+ if '@' in repo_url and ':' in repo_url:
+ # SSH URL format: [user@]host:path
+ repo_name = repo_url.rsplit(':', 1)[-1]
+ else:
+ repo_name = repo_url.rsplit('/', 1)[-1]
+
+ if repo_type == 'git':
+ repo_name = repo_name.rsplit('.git', 1)[0]
+ elif repo_type == 'hg':
+ repo_name = repo_name.rsplit('.hg', 1)[0]
+
+ # Remove existing repo if no_input=True, otherwise prompt
+ repo_dir = os.path.join(clone_to_dir, repo_name)
+ if os.path.exists(repo_dir):
+ if no_input:
+ logger.debug('Removing %s', repo_dir)
+ subprocess.check_output(['rm', '-rf', repo_dir])
+ else:
+ if not prompt_and_delete(repo_dir):
+ return repo_dir
+
+ # Clone the repo
+ clone_cmd = [repo_type, 'clone', repo_url]
+ if repo_type == 'git':
+ clone_cmd.append(repo_name)
+
+ logger.debug('Running command: %s', ' '.join(clone_cmd))
+ try:
+ subprocess.check_output(clone_cmd, cwd=str(clone_to_dir), stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ output = e.output.decode('utf-8')
+ if 'not found' in output.lower():
+ raise RepositoryNotFound(
+ f'The repository {repo_url} could not be found, '
+ 'have you made a typo?'
+ ) from e
+ raise RepositoryCloneFailed(
+ f'Failed to clone repository {repo_url}:\n{output}'
+ ) from e
+ except Exception as e:
+ raise RepositoryCloneFailed(
+ f'Failed to clone repository {repo_url}:\n{str(e)}'
+ ) from e
+
+ # Checkout specific branch, tag, or commit
+ if checkout is not None:
+ checkout_cmd = None
+ if repo_type == 'git':
+ checkout_cmd = ['git', 'checkout', checkout]
+ elif repo_type == 'hg':
+ checkout_cmd = ['hg', 'update', checkout]
+
+ try:
+ subprocess.check_output(checkout_cmd, cwd=str(repo_dir), stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ output = e.output.decode('utf-8')
+ if any(error in output for error in BRANCH_ERRORS):
+ raise RepositoryCloneFailed(
+ 'The {} branch of repository {} could not be found, '
+ 'have you made a typo?'.format(checkout, repo_url)
+ ) from e
+ raise RepositoryCloneFailed(
+ f'Failed to checkout {checkout}:\n{output}'
+ ) from e
+ except Exception as e:
+ raise RepositoryCloneFailed(
+ f'Failed to checkout {checkout}:\n{str(e)}'
+ ) from e
+
+ # Convert repo_dir to string to match test expectations
+ return str(repo_dir).rstrip('/')
\ No newline at end of file
diff --git a/cookiecutter/zipfile.py b/cookiecutter/zipfile.py
index 4e29732..faebe53 100644
--- a/cookiecutter/zipfile.py
+++ b/cookiecutter/zipfile.py
@@ -22,5 +22,109 @@ def unzip(zip_uri: str, is_url: bool, clone_to_dir: 'os.PathLike[str]'='.', no_i
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:param password: The password to use when unpacking the repository.
+ :raises: InvalidZipRepository if the zip file is not a valid cookiecutter template.
+ :returns: The path to the unpacked template.
"""
- pass
\ No newline at end of file
+ # Ensure clone_to_dir exists
+ clone_to_dir = os.path.expanduser(clone_to_dir)
+ clone_to_dir = os.path.normpath(clone_to_dir)
+ make_sure_path_exists(clone_to_dir)
+
+ if is_url:
+ # Build cache path and download if needed
+ zip_path = os.path.join(clone_to_dir, os.path.basename(zip_uri))
+ if os.path.exists(zip_path):
+ if no_input:
+ os.remove(zip_path)
+ else:
+ download = prompt_and_delete(zip_path)
+ if not download:
+ return zip_path
+
+ # Download the zip file
+ response = requests.get(zip_uri, stream=True)
+ response.raise_for_status()
+
+ with open(zip_path, 'wb') as f:
+ for chunk in response.iter_content(chunk_size=1024):
+ if chunk: # filter out keep-alive new chunks
+ f.write(chunk)
+ else:
+ zip_path = os.path.abspath(zip_uri)
+ if not os.path.exists(zip_path):
+ raise InvalidZipRepository(
+ f'Zip file {zip_path} does not exist'
+ )
+
+ # Create a temporary directory for the unzipped contents
+ temp_dir = tempfile.mkdtemp(prefix='cookiecutter-', suffix='-unzip')
+
+ try:
+ # Get password if needed but not provided
+ pwd = password
+ if pwd is None:
+ pwd = os.environ.get('COOKIECUTTER_REPO_PASSWORD')
+
+ with ZipFile(zip_path) as zip_file:
+ # Check if zip file is empty
+ namelist = zip_file.namelist()
+ if not namelist:
+ raise InvalidZipRepository(
+ 'Zip file is empty'
+ )
+
+ # Check if password protected
+ try:
+ # Try to read first file to check if password is needed
+ zip_file.read(namelist[0], pwd=pwd.encode('utf-8') if pwd else None)
+ except RuntimeError:
+ if no_input:
+ raise InvalidZipRepository(
+ 'Zip file is password protected but no password provided'
+ )
+ pwd = read_repo_password('Zip is password protected. Please enter the password')
+ try:
+ zip_file.read(namelist[0], pwd=pwd.encode('utf-8'))
+ except RuntimeError as e:
+ raise InvalidZipRepository(
+ 'Invalid password provided for protected repository'
+ ) from e
+
+ # Find base directory
+ if namelist[0].endswith('/'):
+ base_dir = namelist[0]
+ else:
+ base_dir = os.path.commonprefix(namelist).rstrip('/')
+
+ if not base_dir:
+ raise InvalidZipRepository(
+ 'CookieCutter templates must have a top level directory'
+ )
+
+ # Extract files
+ try:
+ zip_file.extractall(temp_dir, pwd=pwd.encode('utf-8') if pwd else None)
+ except (RuntimeError, BadZipFile) as e:
+ raise InvalidZipRepository(
+ 'Unable to extract zip file contents'
+ ) from e
+
+ # Check that the unzipped dir contains a cookiecutter.json
+ base_dir_path = os.path.join(temp_dir, base_dir)
+ if not os.path.isdir(base_dir_path):
+ raise InvalidZipRepository(
+ 'Zip file does not contain a valid template directory'
+ )
+
+ dir_contents = os.listdir(base_dir_path)
+ if 'cookiecutter.json' not in dir_contents:
+ raise InvalidZipRepository(
+ 'Zip repository does not contain a cookiecutter.json file'
+ )
+
+ return base_dir_path
+
+ except (BadZipFile, RuntimeError) as e:
+ raise InvalidZipRepository(
+ 'Invalid zip file, not a valid cookiecutter template'
+ ) from e
\ No newline at end of file
diff --git a/tests/test-hooks/hooks/pre_gen_project.py b/tests/test-hooks/hooks/pre_gen_project.py
new file mode 100644
index 0000000..f4c3919
--- /dev/null
+++ b/tests/test-hooks/hooks/pre_gen_project.py
@@ -0,0 +1,2 @@
+#!/usr/bin/env python
+import sys; sys.exit(1)