def test_run_json_dump( monkeypatch, mocker, mock_ensure_success, mock_user_config, template_name, context, replay_test_dir, replay_file, ): """Test that replay.dump runs json.dump under the hood and that the context \ is correctly written to the expected file in the replay_dir.""" test_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..') monkeypatch.chdir(test_dir) spy_get_replay_file = mocker.spy(replay, 'get_file_name') mock_json_dump = mocker.patch('json.dump', side_effect=json.dump) replay.dump(replay_test_dir, template_name, context) assert not mock_user_config.called mock_ensure_success.assert_called_once_with(replay_test_dir) spy_get_replay_file.assert_called_once_with(replay_test_dir, template_name) assert mock_json_dump.call_count == 1 (dumped_context, outfile_handler), kwargs = mock_json_dump.call_args assert outfile_handler.name == replay_file assert dumped_context == context
def test_ioerror_if_replay_dir_creation_fails(mock_ensure_failure, mock_user_config, replay_test_dir): """Test that replay.dump raises when the replay_dir cannot be created.""" with pytest.raises(IOError): replay.dump("foo", {"cookiecutter": {"hello": "world"}}) mock_ensure_failure.assert_called_once_with(replay_test_dir)
def test_ioerror_if_replay_dir_creation_fails(mock_ensure_failure, mock_user_config, replay_test_dir): """Test that replay.dump raises when the replay_dir cannot be created.""" with pytest.raises(IOError): replay.dump('foo', {'cookiecutter': {'hello': 'world'}}) mock_ensure_failure.assert_called_once_with(replay_test_dir)
def test_ioerror_if_replay_dir_creation_fails(mock_ensure_failure, replay_test_dir): """Test that replay.dump raises when the replay_dir cannot be created.""" with pytest.raises(IOError): replay.dump(replay_test_dir, "foo", {"cookiecutter": { "hello": "world" }}) mock_ensure_failure.assert_called_once_with(replay_test_dir)
def test_ioerror_if_replay_dir_creation_fails( mock_ensure_failure, replay_test_dir): """Test that replay.dump raises when the replay_dir cannot be created.""" with pytest.raises(IOError): replay.dump( replay_test_dir, 'foo', {'cookiecutter': {'hello': 'world'}} ) mock_ensure_failure.assert_called_once_with(replay_test_dir)
def test_run_json_dump(mocker, mock_ensure_success, mock_user_config, template_name, context, replay_test_dir, replay_file): """Test that replay.dump runs json.dump under the hood and that the context is correctly written to the expected file in the replay_dir. """ spy_get_replay_file = mocker.spy(replay, 'get_file_name') mock_json_dump = mocker.patch('json.dump', side_effect=json.dump) replay.dump(replay_test_dir, template_name, context) assert not mock_user_config.called mock_ensure_success.assert_called_once_with(replay_test_dir) spy_get_replay_file.assert_called_once_with(replay_test_dir, template_name) assert mock_json_dump.call_count == 1 (dumped_context, outfile_handler), kwargs = mock_json_dump.call_args assert outfile_handler.name == replay_file assert dumped_context == context
def test_type_error_if_not_dict_context(replay_test_dir, template_name): """Test that replay.dump raises if the context is not of type dict.""" with pytest.raises(TypeError): replay.dump(replay_test_dir, template_name, 'not_a_dict')
def test_type_error_if_no_template_name(replay_test_dir, context): """Test that replay.dump raises if the template_name is not a valid str.""" with pytest.raises(TypeError): replay.dump(replay_test_dir, None, context)
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): replay.dump(replay_test_dir, template_name, {'foo': 'bar'})
def cookiecutter( template, 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, ): """ 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: Prompt the user at command line for manual configuration? :param extra_context: A dictionary of context that overrides default and user configuration. :param overwrite_if_exists: Overwrite the contents of 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. """ if replay and ((no_input is not False) or (extra_context is not None)): err_msg = ("You can not use both replay and no_input or extra_context " "at the same time.") raise InvalidModeException(err_msg) config_dict = get_user_config( config_file=config_file, default_config=default_config, ) 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, ) template_name = os.path.basename(os.path.abspath(repo_dir)) if replay: context = load(config_dict['replay_dir'], template_name) else: context_file = os.path.join(repo_dir, 'cookiecutter.json') logger.debug('context_file is %s', context_file) context = generate_context( context_file=context_file, default_context=config_dict['default_context'], extra_context=extra_context, ) # prompt the user to manually configure at the command line. # except when 'no-input' flag is set context['cookiecutter'] = prompt_for_config(context, no_input) # include template dir or url in the context dict context['cookiecutter']['_template'] = template dump(config_dict['replay_dir'], template_name, 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, ) # Cleanup (if required) if cleanup: rmtree(repo_dir) return result
def cookiecutter( template='.', checkout=None, no_input=False, context_file=None, context_key=None, existing_context=None, 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, ): """ 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: Prompt the user at command line for manual configuration? :param context_file: The file to load to set the context, ie list of prompts. Defaults to nuki.yaml, nukikata.yml, then cookiecutter.json. :param context_key: The key to all the context under - defaults to the name of the context file minus the file extension. :param existing_context: An additional dictionary to use in rendering additional prompts. :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 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 accept_hooks: Accept pre and post hooks if set to `True`. :return Dictionary of output """ global calling_directory # Preserve this path for special variable usage calling_directory = os.getcwd() if replay and ((no_input is not False) or (extra_context is not None)): err_msg = ("You can not use both replay and no_input or extra_context " "at the same time.") raise InvalidModeException(err_msg) config_dict = get_user_config( config_file=config_file, default_config=default_config, ) repo_dir, context_file, cleanup = determine_repo_dir( template=template, abbreviations=config_dict['abbreviations'], clone_to_dir=config_dict['cookiecutters_dir'], checkout=checkout, no_input=no_input, context_file=context_file, password=password, directory=directory, ) template_name = os.path.basename(os.path.abspath(repo_dir)) if not context_key: context_key = os.path.basename(context_file).split('.')[0] if replay: if isinstance(replay, bool): context = load(config_dict['replay_dir'], template_name, context_key) else: path, template_name = os.path.split(os.path.splitext(replay)[0]) context = load(path, template_name, context_key) else: context_file_path = os.path.join(repo_dir, context_file) logger.debug('context_file is %s', context_file_path) context = generate_context( context_file=context_file_path, default_context=config_dict['default_context'], extra_context=extra_context, context_key=context_key, ) # include template dir or url in the context dict context[context_key]['_template'] = repo_dir # include output+dir in the context dict context[context_key]['_output_dir'] = os.path.abspath(output_dir) # prompt the user to manually configure at the command line.pyth # except when 'no-input' flag is set context[context_key] = prompt_for_config(context, no_input, context_key, existing_context) dump(config_dict['replay_dir'], template_name, context, context_key) # 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, context_key=context_key, accept_hooks=accept_hooks, ) if result: logger.debug('Resulting project directory created at %s', result) else: logger.debug('No project directory was created') # Cleanup (if required) if cleanup: rmtree(repo_dir) if isinstance(context, OrderedDict): context = json.loads(json.dumps(context)) return context[context_key]
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): replay.dump(replay_test_dir, template_name, {'foo': 'bar'})