diff --git a/cookiecutter/cli.py b/cookiecutter/cli.py index 6b3c583ad..a792fa5f5 100644 --- a/cookiecutter/cli.py +++ b/cookiecutter/cli.py @@ -63,9 +63,9 @@ def list_installed_templates(default_config, passed_config_file): os.path.join(cookiecutter_folder, folder, 'cookiecutter.json') ) ] - click.echo('{} installed templates: '.format(len(template_names))) + click.echo(f'{len(template_names)} installed templates: ') for name in template_names: - click.echo(' * {}'.format(name)) + click.echo(f' * {name}') @click.command(context_settings=dict(help_option_names=['-h', '--help'])) @@ -219,11 +219,11 @@ def main( click.echo(e) sys.exit(1) except UndefinedVariableInTemplate as undefined_err: - click.echo('{}'.format(undefined_err.message)) - click.echo('Error message: {}'.format(undefined_err.error.message)) + click.echo(f'{undefined_err.message}') + click.echo(f'Error message: {undefined_err.error.message}') context_str = json.dumps(undefined_err.context, indent=4, sort_keys=True) - click.echo('Context: {}'.format(context_str)) + click.echo(f'Context: {context_str}') sys.exit(1) diff --git a/cookiecutter/config.py b/cookiecutter/config.py index 90483f532..0d0fa8c7e 100644 --- a/cookiecutter/config.py +++ b/cookiecutter/config.py @@ -55,9 +55,7 @@ def merge_configs(default, overwrite): def get_config(config_path): """Retrieve the config from the specified path, returning a config dict.""" if not os.path.exists(config_path): - raise ConfigDoesNotExistException( - 'Config file {} does not exist.'.format(config_path) - ) + raise ConfigDoesNotExistException(f'Config file {config_path} does not exist.') logger.debug('config_path is %s', config_path) with open(config_path, encoding='utf-8') as file_handle: @@ -65,7 +63,7 @@ def get_config(config_path): yaml_dict = yaml.safe_load(file_handle) except yaml.YAMLError as e: raise InvalidConfiguration( - 'Unable to parse YAML file {}.'.format(config_path) + f'Unable to parse YAML file {config_path}.' ) from e config_dict = merge_configs(DEFAULT_CONFIG, yaml_dict) diff --git a/cookiecutter/environment.py b/cookiecutter/environment.py index 2f91e015a..f2804c595 100644 --- a/cookiecutter/environment.py +++ b/cookiecutter/environment.py @@ -4,7 +4,7 @@ from cookiecutter.exceptions import UnknownExtension -class ExtensionLoaderMixin(object): +class ExtensionLoaderMixin: """Mixin providing sane loading of extensions specified in a given context. The context is being extracted from the keyword arguments before calling @@ -32,9 +32,9 @@ def __init__(self, **kwargs): extensions = default_extensions + self._read_extensions(context) try: - super(ExtensionLoaderMixin, self).__init__(extensions=extensions, **kwargs) + super().__init__(extensions=extensions, **kwargs) except ImportError as err: - raise UnknownExtension('Unable to load extension: {}'.format(err)) + raise UnknownExtension(f'Unable to load extension: {err}') def _read_extensions(self, context): """Return list of extensions as str to be passed on to the Jinja2 env. @@ -62,4 +62,4 @@ def __init__(self, **kwargs): Also loading extensions defined in cookiecutter.json's _extensions key. """ - super(StrictEnvironment, self).__init__(undefined=StrictUndefined, **kwargs) + super().__init__(undefined=StrictUndefined, **kwargs) diff --git a/cookiecutter/exceptions.py b/cookiecutter/exceptions.py index 9461aa985..4acf6dc47 100644 --- a/cookiecutter/exceptions.py +++ b/cookiecutter/exceptions.py @@ -124,10 +124,10 @@ def __init__(self, message, error, context): def __str__(self): """Text representation of UndefinedVariableInTemplate.""" return ( - "{self.message}. " - "Error message: {self.error.message}. " - "Context: {self.context}" - ).format(**locals()) + f"{self.message}. " + f"Error message: {self.error.message}. " + f"Context: {self.context}" + ) class UnknownExtension(CookiecutterException): diff --git a/cookiecutter/extensions.py b/cookiecutter/extensions.py index e3a42b244..6a3161aba 100644 --- a/cookiecutter/extensions.py +++ b/cookiecutter/extensions.py @@ -13,7 +13,7 @@ class JsonifyExtension(Extension): def __init__(self, environment): """Initialize the extension with the given environment.""" - super(JsonifyExtension, self).__init__(environment) + super().__init__(environment) def jsonify(obj): return json.dumps(obj, sort_keys=True, indent=4) @@ -26,7 +26,7 @@ class RandomStringExtension(Extension): def __init__(self, environment): """Jinja2 Extension Constructor.""" - super(RandomStringExtension, self).__init__(environment) + super().__init__(environment) def random_ascii_string(length, punctuation=False): if punctuation: @@ -43,7 +43,7 @@ class SlugifyExtension(Extension): def __init__(self, environment): """Jinja2 Extension constructor.""" - super(SlugifyExtension, self).__init__(environment) + super().__init__(environment) def slugify(value, **kwargs): """Slugifies the value.""" @@ -57,7 +57,7 @@ class UUIDExtension(Extension): def __init__(self, environment): """Jinja2 Extension constructor.""" - super(UUIDExtension, self).__init__(environment) + super().__init__(environment) def uuid4(): """Generate UUID4.""" diff --git a/cookiecutter/generate.py b/cookiecutter/generate.py index 7dbd9867b..7bdce5a8b 100644 --- a/cookiecutter/generate.py +++ b/cookiecutter/generate.py @@ -96,8 +96,8 @@ def generate_context( full_fpath = os.path.abspath(context_file) json_exc_message = str(e) our_exc_message = ( - 'JSON decoding error while loading "{0}". Decoding' - ' error details: "{1}"'.format(full_fpath, json_exc_message) + 'JSON decoding error while loading "{}". Decoding' + ' error details: "{}"'.format(full_fpath, json_exc_message) ) raise ContextDecodingException(our_exc_message) @@ -180,7 +180,7 @@ def generate_file(project_dir, infile, context, env, skip_if_file_exists=False): # Detect original file newline to output the rendered file # note: newline='' ensures newlines are not converted - with open(infile, 'r', encoding='utf-8', newline='') as rd: + with open(infile, encoding='utf-8', newline='') as rd: rd.readline() # Read the first line to load 'newlines' value # Use `_new_lines` overwrite from context, if configured. @@ -219,7 +219,7 @@ def render_and_create_dir( 'Output directory %s already exists, overwriting it', dir_to_create ) else: - msg = 'Error: "{}" directory already exists'.format(dir_to_create) + msg = f'Error: "{dir_to_create}" directory already exists' raise OutputDirExistsException(msg) else: make_sure_path_exists(dir_to_create) @@ -292,7 +292,7 @@ def generate_files( unrendered_dir, context, output_dir, env, overwrite_if_exists ) except UndefinedError as err: - msg = "Unable to create project directory '{}'".format(unrendered_dir) + msg = f"Unable to create project directory '{unrendered_dir}'" raise UndefinedVariableInTemplate(msg, err, context) # We want the Jinja path and the OS paths to match. Consequently, we'll: @@ -354,7 +354,7 @@ def generate_files( if delete_project_on_failure: rmtree(project_dir) _dir = os.path.relpath(unrendered_dir, output_dir) - msg = "Unable to create directory '{}'".format(_dir) + msg = f"Unable to create directory '{_dir}'" raise UndefinedVariableInTemplate(msg, err, context) for f in files: @@ -376,7 +376,7 @@ def generate_files( except UndefinedError as err: if delete_project_on_failure: rmtree(project_dir) - msg = "Unable to create file '{}'".format(infile) + msg = f"Unable to create file '{infile}'" raise UndefinedVariableInTemplate(msg, err, context) if accept_hooks: diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py index b6a31a1e0..763287c58 100644 --- a/cookiecutter/hooks.py +++ b/cookiecutter/hooks.py @@ -83,14 +83,14 @@ def run_script(script_path, cwd='.'): exit_status = proc.wait() if exit_status != EXIT_SUCCESS: raise FailedHookException( - 'Hook script failed (exit status: {})'.format(exit_status) + 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 file or missing a shebang' ) - raise FailedHookException('Hook script failed (error: {})'.format(os_error)) + raise FailedHookException(f'Hook script failed (error: {os_error})') def run_script_with_context(script_path, cwd, context): @@ -102,7 +102,7 @@ def run_script_with_context(script_path, cwd, context): """ _, extension = os.path.splitext(script_path) - with open(script_path, 'r', encoding='utf-8') as file: + with open(script_path, encoding='utf-8') as file: contents = file.read() with tempfile.NamedTemporaryFile(delete=False, mode='wb', suffix=extension) as temp: diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py index 4b8b2fbe6..f06cdc3c0 100644 --- a/cookiecutter/prompt.py +++ b/cookiecutter/prompt.py @@ -58,16 +58,14 @@ def read_user_choice(var_name, options): if not options: raise ValueError - choice_map = OrderedDict( - ('{}'.format(i), value) for i, value in enumerate(options, 1) - ) + choice_map = OrderedDict((f'{i}', value) for i, value in enumerate(options, 1)) choices = choice_map.keys() default = '1' choice_lines = ['{} - {}'.format(*c) for c in choice_map.items()] prompt = '\n'.join( ( - 'Select {}:'.format(var_name), + f'Select {var_name}:', '\n'.join(choice_lines), 'Choose from {}'.format(', '.join(choices)), ) @@ -213,7 +211,7 @@ def prompt_for_config(context, no_input=False): cookiecutter_dict[key] = val except UndefinedError as err: - msg = "Unable to render variable '{}'".format(key) + msg = f"Unable to render variable '{key}'" raise UndefinedVariableInTemplate(msg, err, context) # Second pass; handle the dictionaries. @@ -232,7 +230,7 @@ def prompt_for_config(context, no_input=False): cookiecutter_dict[key] = val except UndefinedError as err: - msg = "Unable to render variable '{}'".format(key) + msg = f"Unable to render variable '{key}'" raise UndefinedVariableInTemplate(msg, err, context) return cookiecutter_dict diff --git a/cookiecutter/replay.py b/cookiecutter/replay.py index 504a6a32c..9730e84da 100644 --- a/cookiecutter/replay.py +++ b/cookiecutter/replay.py @@ -12,14 +12,14 @@ def get_file_name(replay_dir, template_name): """Get the name of file.""" suffix = '.json' if not template_name.endswith('.json') else '' - file_name = '{}{}'.format(template_name, suffix) + file_name = f'{template_name}{suffix}' return os.path.join(replay_dir, file_name) def dump(replay_dir, template_name, context): """Write json data to file.""" if not make_sure_path_exists(replay_dir): - raise IOError('Unable to create replay dir at {}'.format(replay_dir)) + raise OSError(f'Unable to create replay dir at {replay_dir}') if not isinstance(template_name, str): raise TypeError('Template name is required to be of type str') @@ -43,7 +43,7 @@ def load(replay_dir, template_name): replay_file = get_file_name(replay_dir, template_name) - with open(replay_file, 'r') as infile: + with open(replay_file) as infile: context = json.load(infile) if 'cookiecutter' not in context: diff --git a/cookiecutter/utils.py b/cookiecutter/utils.py index ef533171a..4750a2663 100644 --- a/cookiecutter/utils.py +++ b/cookiecutter/utils.py @@ -113,7 +113,7 @@ def simple_filter(filter_function): class SimpleFilterExtension(Extension): def __init__(self, environment): - super(SimpleFilterExtension, self).__init__(environment) + super().__init__(environment) environment.filters[filter_function.__name__] = filter_function SimpleFilterExtension.__name__ = filter_function.__name__ diff --git a/cookiecutter/vcs.py b/cookiecutter/vcs.py index d7f7b5ba5..08cb2eb0c 100644 --- a/cookiecutter/vcs.py +++ b/cookiecutter/vcs.py @@ -73,7 +73,7 @@ def clone(repo_url, checkout=None, clone_to_dir='.', no_input=False): # check that the appropriate VCS for the repo_type is installed if not is_vcs_installed(repo_type): - msg = "'{0}' is not installed.".format(repo_type) + msg = f"'{repo_type}' is not installed." raise VCSNotInstalled(msg) repo_url = repo_url.rstrip('/') @@ -83,7 +83,7 @@ def clone(repo_url, checkout=None, clone_to_dir='.', no_input=False): repo_dir = os.path.normpath(os.path.join(clone_to_dir, repo_name)) if repo_type == 'hg': repo_dir = os.path.normpath(os.path.join(clone_to_dir, repo_name)) - logger.debug('repo_dir is {0}'.format(repo_dir)) + logger.debug(f'repo_dir is {repo_dir}') if os.path.isdir(repo_dir): clone = prompt_and_delete(repo_dir, no_input=no_input) diff --git a/cookiecutter/zipfile.py b/cookiecutter/zipfile.py index 24925c7fc..7395ce61b 100644 --- a/cookiecutter/zipfile.py +++ b/cookiecutter/zipfile.py @@ -55,7 +55,7 @@ def unzip(zip_uri, is_url, clone_to_dir='.', no_input=False, password=None): zip_file = ZipFile(zip_path) if len(zip_file.namelist()) == 0: - raise InvalidZipRepository('Zip repository {} is empty'.format(zip_uri)) + raise InvalidZipRepository(f'Zip repository {zip_uri} is empty') # The first record in the zipfile should be the directory entry for # the archive. If it isn't a directory, there's a problem. @@ -106,7 +106,7 @@ def unzip(zip_uri, is_url, clone_to_dir='.', no_input=False, password=None): except BadZipFile: raise InvalidZipRepository( - 'Zip repository {} is not a valid zip archive:'.format(zip_uri) + f'Zip repository {zip_uri} is not a valid zip archive:' ) return unzip_path diff --git a/tests/replay/test_dump.py b/tests/replay/test_dump.py index ec8010b3e..c757321b1 100644 --- a/tests/replay/test_dump.py +++ b/tests/replay/test_dump.py @@ -16,7 +16,7 @@ def template_name(): @pytest.fixture def replay_file(replay_test_dir, template_name): """Fixture to return a actual file name of the dump.""" - file_name = '{}.json'.format(template_name) + file_name = f'{template_name}.json' return os.path.join(replay_test_dir, file_name) diff --git a/tests/replay/test_load.py b/tests/replay/test_load.py index a64a285e1..c8bc453e0 100644 --- a/tests/replay/test_load.py +++ b/tests/replay/test_load.py @@ -16,7 +16,7 @@ def template_name(): @pytest.fixture def replay_file(replay_test_dir, template_name): """Fixture to return a actual file name of the dump.""" - file_name = '{}.json'.format(template_name) + file_name = f'{template_name}.json' return os.path.join(replay_test_dir, file_name) diff --git a/tests/test-extensions/hello_extension/hello_extension.py b/tests/test-extensions/hello_extension/hello_extension.py index f54b6efdd..07f3753b9 100644 --- a/tests/test-extensions/hello_extension/hello_extension.py +++ b/tests/test-extensions/hello_extension/hello_extension.py @@ -6,15 +6,15 @@ class HelloExtension(Extension): """Simple jinja2 extension for cookiecutter test purposes.""" - tags = set(['hello']) + tags = {'hello'} def __init__(self, environment): """Hello Extension Constructor.""" - super(HelloExtension, self).__init__(environment) + super().__init__(environment) def _hello(self, name): """Do actual tag replace when invoked by parser.""" - return 'Hello {name}!'.format(name=name) + return f'Hello {name}!' def parse(self, parser): """Work when something match `tags` variable.""" diff --git a/tests/test-extensions/local_extension/local_extensions/main.py b/tests/test-extensions/local_extension/local_extensions/main.py index 53f6f8f95..b18a25c91 100644 --- a/tests/test-extensions/local_extension/local_extensions/main.py +++ b/tests/test-extensions/local_extension/local_extensions/main.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """Provides custom extension, exposing a ``foobar`` filter.""" from jinja2.ext import Extension @@ -11,7 +9,7 @@ class FoobarExtension(Extension): def __init__(self, environment): """Foobar Extension Constructor.""" - super(FoobarExtension, self).__init__(environment) + super().__init__(environment) environment.filters['foobar'] = lambda v: v * 2 diff --git a/tests/test_default_extensions.py b/tests/test_default_extensions.py index e73ef9c1b..540138d31 100644 --- a/tests/test_default_extensions.py +++ b/tests/test_default_extensions.py @@ -25,7 +25,7 @@ def test_jinja2_time_extension(tmp_path): changelog_file = os.path.join(project_dir, 'HISTORY.rst') assert os.path.isfile(changelog_file) - with open(changelog_file, 'r', encoding='utf-8') as f: + with open(changelog_file, encoding='utf-8') as f: changelog_lines = f.readlines() expected_lines = [ @@ -57,7 +57,7 @@ def test_jinja2_uuid_extension(tmp_path): changelog_file = os.path.join(project_dir, 'id') assert os.path.isfile(changelog_file) - with open(changelog_file, 'r', encoding='utf-8') as f: + with open(changelog_file, encoding='utf-8') as f: changelog_lines = f.readlines() uuid.UUID(changelog_lines[0], version=4) diff --git a/tests/test_generate_file.py b/tests/test_generate_file.py index a393a2ef8..18c811eea 100644 --- a/tests/test_generate_file.py +++ b/tests/test_generate_file.py @@ -45,7 +45,7 @@ def test_generate_file(env): env=env, ) assert os.path.isfile('tests/files/cheese.txt') - with open('tests/files/cheese.txt', 'rt') as f: + with open('tests/files/cheese.txt') as f: generated_text = f.read() assert generated_text == 'Testing cheese' @@ -58,7 +58,7 @@ def test_generate_file_jsonify_filter(env): project_dir=".", infile=infile, context={'cookiecutter': data}, env=env ) assert os.path.isfile('tests/files/cheese.txt') - with open('tests/files/cheese.txt', 'rt') as f: + with open('tests/files/cheese.txt') as f: generated_text = f.read() assert json.loads(generated_text) == data @@ -72,7 +72,7 @@ def test_generate_file_random_ascii_string(env, length, punctuation): context = {"cookiecutter": data, "length": length, "punctuation": punctuation} generate.generate_file(project_dir=".", infile=infile, context=context, env=env) assert os.path.isfile('tests/files/cheese.txt') - with open('tests/files/cheese.txt', 'rt') as f: + with open('tests/files/cheese.txt') as f: generated_text = f.read() assert len(generated_text) == length @@ -92,7 +92,7 @@ def test_generate_file_with_true_condition(env): env=env, ) assert os.path.isfile('tests/files/cheese.txt') - with open('tests/files/cheese.txt', 'rt') as f: + with open('tests/files/cheese.txt') as f: generated_text = f.read() assert generated_text == 'Testing that generate_file was y' @@ -148,7 +148,7 @@ def test_generate_file_does_not_translate_lf_newlines_to_crlf(env, tmp_path): # this generated file should have a LF line ending gf = 'tests/files/cheese_lf_newlines.txt' - with open(gf, 'r', encoding='utf-8', newline='') as f: + with open(gf, encoding='utf-8', newline='') as f: simple_text = f.readline() assert simple_text == 'newline is LF\n' assert f.newlines == '\n' @@ -166,7 +166,7 @@ def test_generate_file_does_not_translate_crlf_newlines_to_lf(env): # this generated file should have a CRLF line ending gf = 'tests/files/cheese_crlf_newlines.txt' - with open(gf, 'r', encoding='utf-8', newline='') as f: + with open(gf, encoding='utf-8', newline='') as f: simple_text = f.readline() assert simple_text == 'newline is CRLF\r\n' assert f.newlines == '\r\n' diff --git a/tests/test_generate_files.py b/tests/test_generate_files.py index 4e21c7053..4d6ef1113 100644 --- a/tests/test_generate_files.py +++ b/tests/test_generate_files.py @@ -44,7 +44,7 @@ def test_generate_files(tmp_path): assert simple_file.exists() assert simple_file.is_file() - simple_text = open(simple_file, 'rt', encoding='utf-8').read() + simple_text = open(simple_file, encoding='utf-8').read() assert simple_text == 'I eat pizzä' @@ -60,7 +60,7 @@ def test_generate_files_with_linux_newline(tmp_path): assert newline_file.is_file() assert newline_file.exists() - with open(newline_file, 'r', encoding='utf-8', newline='') as f: + with open(newline_file, encoding='utf-8', newline='') as f: simple_text = f.readline() assert simple_text == 'newline is LF\n' assert f.newlines == '\n' @@ -84,7 +84,7 @@ def test_generate_files_with_jinja2_environment(tmp_path): assert conditions_file.exists() simple_text = conditions_file.open('rt', encoding='utf-8').read() - assert simple_text == u'I eat pizzä\n' + assert simple_text == 'I eat pizzä\n' def test_generate_files_with_trailing_newline_forced_to_linux_by_context(tmp_path): @@ -100,7 +100,7 @@ def test_generate_files_with_trailing_newline_forced_to_linux_by_context(tmp_pat assert newline_file.is_file() assert newline_file.exists() - with open(newline_file, 'r', encoding='utf-8', newline='') as f: + with open(newline_file, encoding='utf-8', newline='') as f: simple_text = f.readline() assert simple_text == 'newline is LF\r\n' assert f.newlines == '\r\n' @@ -118,7 +118,7 @@ def test_generate_files_with_windows_newline(tmp_path): assert newline_file.is_file() assert newline_file.exists() - with open(newline_file, 'r', encoding='utf-8', newline='') as f: + with open(newline_file, encoding='utf-8', newline='') as f: simple_text = f.readline() assert simple_text == 'newline is CRLF\r\n' assert f.newlines == '\r\n' @@ -136,7 +136,7 @@ def test_generate_files_with_windows_newline_forced_to_linux_by_context(tmp_path assert newline_file.is_file() assert newline_file.exists() - with open(newline_file, 'r', encoding='utf-8', newline='') as f: + with open(newline_file, encoding='utf-8', newline='') as f: simple_text = f.readline() assert simple_text == 'newline is CRLF\n' @@ -257,7 +257,7 @@ def test_generate_files_with_overwrite_if_exists_with_skip_if_file_exists(tmp_pa assert Path(simple_with_new_line_file).is_file() assert Path(simple_with_new_line_file).exists() - simple_text = open(simple_file, 'rt', encoding='utf-8').read() + simple_text = open(simple_file, encoding='utf-8').read() assert simple_text == 'temp' @@ -283,7 +283,7 @@ def test_generate_files_with_skip_if_file_exists(tmp_path): assert not Path(simple_with_new_line_file).is_file() assert not Path(simple_with_new_line_file).exists() - simple_text = open(simple_file, 'rt', encoding='utf-8').read() + simple_text = open(simple_file, encoding='utf-8').read() assert simple_text == 'temp' @@ -308,7 +308,7 @@ def test_generate_files_with_overwrite_if_exists(tmp_path): assert Path(simple_with_new_line_file).is_file() assert Path(simple_with_new_line_file).exists() - simple_text = open(simple_file, 'rt', encoding='utf-8').read() + simple_text = open(simple_file, encoding='utf-8').read() assert simple_text == 'I eat pizzä' @@ -382,7 +382,7 @@ def test_raise_undefined_variable_dir_name(output_dir, undefined_context): error = err.value directory = Path('testproject', '{{cookiecutter.foobar}}') - msg = "Unable to create directory '{}'".format(directory) + msg = f"Unable to create directory '{directory}'" assert msg == error.message assert error.context == undefined_context @@ -407,7 +407,7 @@ def test_raise_undefined_variable_dir_name_existing_project( error = err.value directory = Path('testproject', '{{cookiecutter.foobar}}') - msg = "Unable to create directory '{}'".format(directory) + msg = f"Unable to create directory '{directory}'" assert msg == error.message assert error.context == undefined_context diff --git a/tests/test_hooks.py b/tests/test_hooks.py index d8b55dff2..d214e714b 100644 --- a/tests/test_hooks.py +++ b/tests/test_hooks.py @@ -71,7 +71,7 @@ def make_test_repo(name, multiple_hooks=False): return post -class TestFindHooks(object): +class TestFindHooks: """Class to unite find hooks related tests in one place.""" repo_path = 'tests/test-hooks' @@ -91,7 +91,7 @@ def test_find_hook(self): actual_hook_path = hooks.find_hook('pre_gen_project') assert expected_pre == actual_hook_path[0] - expected_post = os.path.abspath('hooks/{}'.format(self.post_hook)) + expected_post = os.path.abspath(f'hooks/{self.post_hook}') actual_hook_path = hooks.find_hook('post_gen_project') assert expected_post == actual_hook_path[0] @@ -111,7 +111,7 @@ def test_hook_not_found(self): assert hooks.find_hook('unknown_hook') is None -class TestExternalHooks(object): +class TestExternalHooks: """Class to unite tests for hooks with different project paths.""" repo_path = os.path.abspath('tests/test-hooks/') @@ -154,7 +154,7 @@ def test_run_failing_script(self, mocker): with pytest.raises(exceptions.FailedHookException) as excinfo: hooks.run_script(os.path.join(self.hooks_path, self.post_hook)) - assert 'Hook script failed (error: {})'.format(err) in str(excinfo.value) + assert f'Hook script failed (error: {err})' in str(excinfo.value) def test_run_failing_script_enoexec(self, mocker): """Test correct exception raise if run_script fails.""" diff --git a/tests/test_prompt.py b/tests/test_prompt.py index 8187cb283..037591dd4 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -66,7 +66,7 @@ def test_convert_to_str_complex_variables(self, raw_var, rendered_var): assert result == rendered_var -class TestPrompt(object): +class TestPrompt: """Class to unite user prompt related tests.""" @pytest.mark.parametrize( @@ -210,11 +210,11 @@ def test_should_render_private_variables_with_two_underscores(self): [ ('foo', 'Hello world'), ('bar', 123), - ('rendered_foo', u'{{ cookiecutter.foo|lower }}'), + ('rendered_foo', '{{ cookiecutter.foo|lower }}'), ('rendered_bar', 123), - ('_hidden_foo', u'{{ cookiecutter.foo|lower }}'), + ('_hidden_foo', '{{ cookiecutter.foo|lower }}'), ('_hidden_bar', 123), - ('__rendered_hidden_foo', u'{{ cookiecutter.foo|lower }}'), + ('__rendered_hidden_foo', '{{ cookiecutter.foo|lower }}'), ('__rendered_hidden_bar', 123), ] ) @@ -226,7 +226,7 @@ def test_should_render_private_variables_with_two_underscores(self): ('bar', '123'), ('rendered_foo', 'hello world'), ('rendered_bar', '123'), - ('_hidden_foo', u'{{ cookiecutter.foo|lower }}'), + ('_hidden_foo', '{{ cookiecutter.foo|lower }}'), ('_hidden_bar', 123), ('__rendered_hidden_foo', 'hello world'), ('__rendered_hidden_bar', '123'), @@ -252,7 +252,7 @@ def test_should_not_render_private_variables(self): assert cookiecutter_dict == context['cookiecutter'] -class TestReadUserChoice(object): +class TestReadUserChoice: """Class to unite choices prompt related tests.""" def test_should_invoke_read_user_choice(self, mocker): @@ -332,7 +332,7 @@ def test_should_render_choices(self, mocker): assert cookiecutter_dict == expected -class TestPromptChoiceForConfig(object): +class TestPromptChoiceForConfig: """Class to unite choices prompt related tests with config test.""" @pytest.fixture diff --git a/tests/test_read_user_choice.py b/tests/test_read_user_choice.py index ef9ae62f4..f3573593c 100644 --- a/tests/test_read_user_choice.py +++ b/tests/test_read_user_choice.py @@ -24,7 +24,7 @@ def test_click_invocation(mocker, user_choice, expected_value): choice.return_value = click.Choice(OPTIONS) prompt = mocker.patch('click.prompt') - prompt.return_value = '{}'.format(user_choice) + prompt.return_value = f'{user_choice}' assert read_user_choice('varname', OPTIONS) == expected_value diff --git a/tests/vcs/test_clone.py b/tests/vcs/test_clone.py index cd4ac13d7..9fc3b24fa 100644 --- a/tests/vcs/test_clone.py +++ b/tests/vcs/test_clone.py @@ -130,10 +130,8 @@ def test_clone_should_invoke_vcs_command( @pytest.mark.parametrize( 'error_message', [ - ( - "fatal: repository 'https://github.com/hackebro/cookiedozer' not found" - ).encode('utf-8'), - 'hg: abort: HTTP Error 404: Not Found'.encode('utf-8'), + (b"fatal: repository 'https://github.com/hackebro/cookiedozer' not found"), + b'hg: abort: HTTP Error 404: Not Found', ], ) def test_clone_handles_repo_typo(mocker, clone_dir, error_message): @@ -160,10 +158,8 @@ def test_clone_handles_repo_typo(mocker, clone_dir, error_message): @pytest.mark.parametrize( 'error_message', [ - ( - "error: pathspec 'unknown_branch' did not match any file(s) known to git" - ).encode('utf-8'), - "hg: abort: unknown revision 'unknown_branch'!".encode('utf-8'), + 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): @@ -196,9 +192,7 @@ def test_clone_unknown_subprocess_error(mocker, clone_dir): 'cookiecutter.vcs.subprocess.check_output', autospec=True, side_effect=[ - subprocess.CalledProcessError( - -1, 'cmd', output='Something went wrong'.encode('utf-8') - ) + subprocess.CalledProcessError(-1, 'cmd', output=b'Something went wrong') ], )