diff --git a/copier/__init__.py b/copier/__init__.py index 664a838fb..80e92eb7f 100644 --- a/copier/__init__.py +++ b/copier/__init__.py @@ -3,7 +3,7 @@ Docs: https://copier.readthedocs.io/ """ -from .main import * # noqa: F401,F403 +from .main import * # noqa: F403 # This version is a placeholder autoupdated by poetry-dynamic-versioning __version__ = "0.0.0" diff --git a/copier/cli.py b/copier/cli.py index 47532c12d..caa5e46b5 100644 --- a/copier/cli.py +++ b/copier/cli.py @@ -68,8 +68,8 @@ def _handle_exceptions(method: Callable[[], None]) -> int: try: try: method() - except KeyboardInterrupt: - raise UserMessageError("Execution stopped by user") + except KeyboardInterrupt as error: + raise UserMessageError("Execution stopped by user") from error except UserMessageError as error: print(colors.red | "\n".join(error.args), file=sys.stderr) return 1 @@ -201,7 +201,7 @@ def _worker( self, src_path: Optional[str] = None, dst_path: str = ".", - **kwargs: Any, # noqa: FA100 + **kwargs: Any, ) -> Worker: """Run Copier's internal API using CLI switches. diff --git a/copier/errors.py b/copier/errors.py index 01e6f1ad0..6fbdba4e6 100644 --- a/copier/errors.py +++ b/copier/errors.py @@ -72,7 +72,7 @@ class ExtensionNotFoundError(UserMessageError): """Extensions listed in the configuration could not be loaded.""" -class CopierAnswersInterrupt(CopierError, KeyboardInterrupt): +class CopierAnswersInterruptError(CopierError, KeyboardInterrupt): """CopierAnswersInterrupt is raised during interactive question prompts. It typically follows a KeyboardInterrupt (i.e. ctrl-c) and provides an @@ -108,7 +108,8 @@ def __init__(self, features: Sequence[str]): s = "s" if len(features) > 1 else "" super().__init__( f"Template uses potentially unsafe feature{s}: {', '.join(features)}.\n" - "If you trust this template, consider adding the `--trust` option when running `copier copy/update`." + "If you trust this template, consider adding the `--trust` option when " + "running `copier copy/update`." ) diff --git a/copier/jinja_ext.py b/copier/jinja_ext.py index 24d8f83cb..39274dbe0 100644 --- a/copier/jinja_ext.py +++ b/copier/jinja_ext.py @@ -19,15 +19,15 @@ class YieldEnvironment(SandboxedEnvironment): This is simple environment class that extends the SandboxedEnvironment for use with the YieldExtension, mainly for avoiding type errors. - We use the SandboxedEnvironment because we want to minimize the risk of hidden malware - in the templates. Of course we still have the post-copy tasks to worry about, but at least - they are more visible to the final user. + We use the SandboxedEnvironment because we want to minimize the risk of hidden + malware in the templates. Of course we still have the post-copy tasks to worry + about, but at least they are more visible to the final user. """ yield_name: str | None yield_iterable: Iterable[Any] | None - def __init__(self, *args: Any, **kwargs: Any): + def __init__(self, *args: Any, **kwargs: Any): # noqa: D107 super().__init__(*args, **kwargs) self.extend(yield_name=None, yield_iterable=None) @@ -58,9 +58,9 @@ class YieldExtension(Extension): >>> env.yield_iterable [1, 2, 3] ``` - """ + """ # noqa: E501 - tags = {"yield"} + tags = {"yield"} # noqa: RUF012 environment: YieldEnvironment @@ -97,16 +97,19 @@ def _yield_support( ) -> str: """Support function for the yield tag. - Sets the `yield_name` and `yield_iterable` attributes in the environment then calls - the provided caller function. If an UndefinedError is raised, it returns an empty string. + Sets the `yield_name` and `yield_iterable` attributes in the environment then + calls the provided caller function. If an UndefinedError is raised, it returns + an empty string. """ if ( self.environment.yield_name is not None or self.environment.yield_iterable is not None ): raise MultipleYieldTagsError( - "Attempted to parse the yield tag twice. Only one yield tag is allowed per path name.\n" - f'A yield tag with the name: "{self.environment.yield_name}" and iterable: "{self.environment.yield_iterable}" already exists.' + "Attempted to parse the yield tag twice. Only one yield tag is allowed" + " per path name.\n" + f'A yield tag with the name: "{self.environment.yield_name}" and ' + f'iterable: "{self.environment.yield_iterable}" already exists.' ) self.environment.yield_name = yield_name diff --git a/copier/main.py b/copier/main.py index 84dc32bf9..20addeda6 100644 --- a/copier/main.py +++ b/copier/main.py @@ -39,7 +39,7 @@ from questionary import unsafe_prompt from .errors import ( - CopierAnswersInterrupt, + CopierAnswersInterruptError, ExtensionNotFoundError, UnsafeTemplateError, UserMessageError, @@ -201,7 +201,7 @@ class Worker: skip_tasks: When `True`, skip template tasks execution. - """ + """ # noqa: E501 src_path: str | None = None dst_path: Path = Path() @@ -359,7 +359,8 @@ def _execute_tasks(self, tasks: Sequence[Task]) -> None: continue working_directory = ( - # We can't use _render_path here, as that function has special handling for files in the template + # We can't use _render_path here, as that function has special handling + # for files in the template self.subproject.local_abspath / Path(self._render_string(str(task.working_directory), extra_context)) ).absolute() @@ -389,13 +390,13 @@ def _system_render_context(self) -> AnyByStrMutableMapping: "os": OS, } ) - return dict( - _copier_answers=self._answers_to_remember(), - _copier_conf=conf, - _external_data=self._external_data(), - _folder_name=self.subproject.local_abspath.name, - _copier_python=sys.executable, - ) + return { + "_copier_answers": self._answers_to_remember(), + "_copier_conf": conf, + "_external_data": self._external_data(), + "_folder_name": self.subproject.local_abspath.name, + "_copier_python": sys.executable, + } def _path_matcher(self, patterns: Iterable[str]) -> Callable[[Path], bool]: """Produce a function that matches against specified patterns.""" @@ -560,7 +561,7 @@ def _ask(self) -> None: # noqa: C901 answers={question.var_name: question.get_default()}, )[question.var_name] except KeyboardInterrupt as err: - raise CopierAnswersInterrupt( + raise CopierAnswersInterruptError( self.answers, question, self.template ) from err self.answers.user[var_name] = new_answer @@ -608,7 +609,7 @@ def jinja_env(self) -> YieldEnvironment: f"Copier could not load some Jinja extensions:\n{error}\n" "Make sure to install these extensions alongside Copier itself.\n" "See the docs at https://copier.readthedocs.io/en/latest/configuring/#jinja_extensions" - ) + ) from error # patch the `to_json` filter to support Pydantic dataclasses env.filters["to_json"] = partial( env.filters["to_json"], default=to_jsonable_python @@ -700,7 +701,8 @@ def _render_file( ).encode() if self.jinja_env.yield_name: raise YieldTagInFileError( - f"File {src_relpath} contains a yield tag, but it is not allowed." + f"File {src_relpath} contains a yield tag, but it is not " + "allowed." ) else: new_content = src_abspath.read_bytes() @@ -797,10 +799,11 @@ def _render_parts( ) -> Iterable[tuple[Path, AnyByStrDict | None]]: """Render a set of parts into path and context pairs. - If a yield tag is found in a part, it will recursively yield multiple path and context pairs. + If a yield tag is found in a part, it will recursively yield multiple path and + context pairs. """ if rendered_parts is None: - rendered_parts = tuple() + rendered_parts = () if not parts: rendered_path = Path(*rendered_parts) @@ -820,7 +823,8 @@ def _render_parts( if not extra_context: extra_context = {} - # If the `part` has a yield tag, `self.jinja_env` will be set with the yield name and iterable + # If the `part` has a yield tag, `self.jinja_env` will be set with the yield + # name and iterable rendered_part = self._render_string(part, extra_context=extra_context) yield_name = self.jinja_env.yield_name @@ -835,7 +839,7 @@ def _render_parts( continue yield from self._render_parts( - parts, rendered_parts + (rendered_part,), new_context, is_template + parts, (*rendered_parts, rendered_part), new_context, is_template ) return @@ -847,7 +851,7 @@ def _render_parts( rendered_part = self._adjust_rendered_part(rendered_part) yield from self._render_parts( - parts, rendered_parts + (rendered_part,), extra_context, is_template + parts, (*rendered_parts, rendered_part), extra_context, is_template ) def _render_path(self, relpath: Path) -> Iterable[tuple[Path, AnyByStrDict | None]]: @@ -959,7 +963,7 @@ def run_copy(self) -> None: self._render_template() if not self.quiet: # TODO Unify printing tools - print("") # padding space + print() # padding space if not self.skip_tasks: self._execute_tasks(self.template.tasks) except Exception: @@ -969,7 +973,7 @@ def run_copy(self) -> None: self._print_message(self.template.message_after_copy) if not self.quiet: # TODO Unify printing tools - print("") # padding space + print() # padding space def run_recopy(self) -> None: """Update a subproject, keeping answers but discarding evolution.""" @@ -1014,8 +1018,8 @@ def run_update(self) -> None: raise UserMessageError("Cannot update: version from template not detected.") if self.subproject.template.version > self.template.version: raise UserMessageError( - f"You are downgrading from {self.subproject.template.version} to {self.template.version}. " - "Downgrades are not supported." + f"You are downgrading from {self.subproject.template.version} to " + f"{self.template.version}. Downgrades are not supported." ) if not self.overwrite: # Only git-tracked subprojects can be updated, so the user can @@ -1101,7 +1105,8 @@ def _apply_update(self) -> None: # noqa: C901 ) ) ) - # Clear last answers cache to load possible answers migration, if skip_answered flag is not set + # Clear last answers cache to load possible answers migration, if + # skip_answered flag is not set if self.skip_answered is False: self.answers = AnswersMap(system=self._system_render_context()) with suppress(AttributeError): @@ -1234,7 +1239,8 @@ def _apply_update(self) -> None: # noqa: C901 Path(f"{fname}.rej").unlink() # The 3-way merge might have resolved conflicts automatically, # so we need to check if the file contains conflict markers - # before storing the file name for marking it as unmerged after the loop. + # before storing the file name for marking it as unmerged after + # the loop. with Path(fname).open() as conflicts_candidate: if any( line.rstrip() @@ -1244,9 +1250,11 @@ def _apply_update(self) -> None: # noqa: C901 conflicted.append(fname) # We ran `git merge-file` outside of a regular merge operation, # which means no merge conflict is recorded in the index. - # Only the usual stage 0 is recorded, with the hash of the current version. - # We therefore update the index with the missing stages: - # 1 = current (before updating), 2 = base (last update), 3 = other (after updating). + # Only the usual stage 0 is recorded, with the hash of the current + # version. We therefore update the index with the missing stages: + # 1 = current (before updating), 2 = base (last update), 3 = other + # (after updating). + # # See this SO post: https://stackoverflow.com/questions/79309642/ # and Git docs: https://git-scm.com/docs/git-update-index#_using_index_info. if conflicted: diff --git a/copier/settings.py b/copier/settings.py index 6a9069bb7..f73bfac72 100644 --- a/copier/settings.py +++ b/copier/settings.py @@ -39,7 +39,7 @@ def from_file(cls, settings_path: Path | None = None) -> Settings: if settings_path.is_file(): data = yaml.safe_load(settings_path.read_text()) return cls.model_validate(data) - elif env_path: + if env_path: warnings.warn( f"Settings file not found at {env_path}", MissingSettingsWarning ) diff --git a/copier/template.py b/copier/template.py index fca1f9292..555c9de7b 100644 --- a/copier/template.py +++ b/copier/template.py @@ -256,11 +256,11 @@ def _raw_config(self) -> AnyByStrDict: conf_paths = [ p for p in self.local_abspath.glob("copier.*") - if p.is_file() and re.match(r"\.ya?ml", p.suffix, re.I) + if p.is_file() and re.match(r"\.ya?ml", p.suffix, re.IGNORECASE) ] if len(conf_paths) > 1: raise MultipleConfigFilesError(conf_paths) - elif len(conf_paths) == 1: + if len(conf_paths) == 1: return load_template_config(conf_paths[0]) return {} @@ -405,7 +405,10 @@ def migration_tasks( if any(key in migration for key in ("before", "after")): # Legacy configuration format warn( - "This migration configuration is deprecated. Please switch to the new format.", + ( + "This migration configuration is deprecated. Please switch to " + "the new format." + ), category=DeprecationWarning, ) current = parse(migration["version"]) diff --git a/copier/tools.py b/copier/tools.py index 28250d39a..3d704d562 100644 --- a/copier/tools.py +++ b/copier/tools.py @@ -14,7 +14,7 @@ from importlib.metadata import version from pathlib import Path from types import TracebackType -from typing import Any, Callable, Iterator, Literal, TextIO, cast +from typing import Any, Callable, ClassVar, Iterator, Literal, TextIO, cast import colorama from packaging.version import Version @@ -27,11 +27,11 @@ class Style: """Common color styles.""" - OK = [colorama.Fore.GREEN, colorama.Style.BRIGHT] - WARNING = [colorama.Fore.YELLOW, colorama.Style.BRIGHT] - IGNORE = [colorama.Fore.CYAN] - DANGER = [colorama.Fore.RED, colorama.Style.BRIGHT] - RESET = [colorama.Fore.RESET, colorama.Style.RESET_ALL] + OK: ClassVar[list[str]] = [colorama.Fore.GREEN, colorama.Style.BRIGHT] + WARNING: ClassVar[list[str]] = [colorama.Fore.YELLOW, colorama.Style.BRIGHT] + IGNORE: ClassVar[list[str]] = [colorama.Fore.CYAN] + DANGER: ClassVar[list[str]] = [colorama.Fore.RED, colorama.Style.BRIGHT] + RESET: ClassVar[list[str]] = [colorama.Fore.RESET, colorama.Style.RESET_ALL] INDENT = " " * 2 @@ -77,7 +77,7 @@ def printf( if not style: return action + _msg - out = style + [action] + Style.RESET + [INDENT, _msg] + out = [*style, action, *Style.RESET, INDENT, _msg] print(*out, sep="", file=file_) return None @@ -87,7 +87,7 @@ def printf_exception( ) -> None: """Print exception with common format.""" if not quiet: - print("", file=sys.stderr) + print(file=sys.stderr) printf(action, msg=msg, style=Style.DANGER, indent=indent, file_=sys.stderr) print(HLINE, file=sys.stderr) print(e, file=sys.stderr) @@ -131,7 +131,7 @@ def cast_to_bool(value: Any) -> bool: lower = value.lower() if lower in {"y", "yes", "t", "true", "on"}: return True - elif lower in {"n", "no", "f", "false", "off", "~", "null", "none"}: + if lower in {"n", "no", "f", "false", "off", "~", "null", "none"}: return False # Assume nothing return bool(value) @@ -152,7 +152,8 @@ def force_str_end(original_str: str, end: str = "\n") -> str: def handle_remove_readonly( func: Callable[[str], None], path: str, - # TODO: Change this union to simply `BaseException` when Python 3.11 support is dropped + # TODO: Change this union to simply `BaseException` when Python 3.11 support is + # dropped exc: BaseException | tuple[type[BaseException], BaseException, TracebackType], ) -> None: """Handle errors when trying to remove read-only files through `shutil.rmtree`. @@ -181,9 +182,9 @@ def handle_remove_readonly( def normalize_git_path(path: str) -> str: r"""Convert weird characters returned by Git to normal UTF-8 path strings. - A filename like âñ will be reported by Git as "\\303\\242\\303\\261" (octal notation). - Similarly, a filename like "foo\bar" will be reported as "\tfoo\\b\nar". - This can be disabled with `git config core.quotepath off`. + A filename like âñ will be reported by Git as "\\303\\242\\303\\261" (octal + notation). Similarly, a filename like "foo\bar" will be reported as + "\tfoo\\b\nar". This can be disabled with `git config core.quotepath off`. Args: path: The Git path to normalize. diff --git a/copier/user_data.py b/copier/user_data.py index 429a3e7a7..62b77240d 100644 --- a/copier/user_data.py +++ b/copier/user_data.py @@ -44,7 +44,7 @@ def _now() -> datetime: def _make_secret() -> str: warnings.warn( "'make_secret' will be removed in a future release of Copier.\n" - "Please use this instead: {{ 999999999999999999999999999999999|ans_random|hash('sha512') }}\n" + "Please use this instead: {{ 999999999999999999999999999999999|ans_random|hash('sha512') }}\n" # noqa: E501 "random and hash filters documentation: https://docs.ansible.com/ansible/2.3/playbooks_filters.html", FutureWarning, ) @@ -263,8 +263,7 @@ def get_default(self) -> Any: result = self.render_value( self.settings.defaults.get(self.var_name, self.default) ) - result = self.cast_answer(result) - return result + return self.cast_answer(result) def get_default_rendered(self) -> bool | str | Choice | None | MissingType: """Get default answer rendered for the questionary lib. @@ -349,9 +348,8 @@ def _formatted_choices(self) -> Sequence[Choice]: def get_message(self) -> str: """Get the message that will be printed to the user.""" - if self.help: - if rendered_help := self.render_value(self.help): - return force_str_end(rendered_help) + " " + if self.help and (rendered_help := self.render_value(self.help)): + return force_str_end(rendered_help) + " " # Otherwise, there's no help message defined. message = self.var_name if (answer_type := self.get_type_name()) != "str": @@ -498,7 +496,7 @@ def parse_yaml_string(string: str) -> Any: try: return yaml.safe_load(string) except yaml.error.YAMLError as error: - raise ValueError(str(error)) + raise ValueError(str(error)) from error def load_answersfile_data( diff --git a/copier/vcs.py b/copier/vcs.py index 1917a7ff3..ba4057e8c 100644 --- a/copier/vcs.py +++ b/copier/vcs.py @@ -84,10 +84,11 @@ def is_git_bundle(path: Path) -> bool: """Indicate if a path is a valid git bundle.""" with suppress(OSError): path = path.resolve() - with TemporaryDirectory(prefix=f"{__name__}.is_git_bundle.") as dirname: - with local.cwd(dirname): - get_git()("init") - return bool(get_git()["bundle", "verify", path] & TF) + with TemporaryDirectory(prefix=f"{__name__}.is_git_bundle.") as dirname, local.cwd( + dirname + ): + get_git()("init") + return bool(get_git()["bundle", "verify", path] & TF) def get_repo(url: str) -> str | None: @@ -113,7 +114,7 @@ def get_repo(url: str) -> str | None: if url.startswith("git+"): return url[4:] if url.startswith("https://") and not url.endswith(GIT_POSTFIX): - return "".join((url, GIT_POSTFIX)) + return f"{url}{GIT_POSTFIX}" return url url_path = Path(url) @@ -181,8 +182,8 @@ def clone(url: str, ref: str | None = None) -> str: file_url = url if is_git_shallow_repo(file_url): warn( - f"The repository '{url}' is a shallow clone, this might lead to unexpected " - "failure or unusually high resource consumption.", + f"The repository '{url}' is a shallow clone, this might lead to " + "unexpected failure or unusually high resource consumption.", ShallowCloneWarning, ) else: diff --git a/devtasks.py b/devtasks.py index 9bcbfb338..dc82df27d 100644 --- a/devtasks.py +++ b/devtasks.py @@ -52,9 +52,10 @@ def lint() -> None: ) except ProcessExecutionError: _logger.info( - "Couldn't create copier-lint-v1 container, probably because a previous one exists. " - "Remove it if you want to recycle it. Otherwise, this is OK." + "Couldn't create copier-lint-v1 container, probably because a previous " + "one exists. Remove it if you want to recycle it. Otherwise, this is " + "OK." ) runner["container", "start", "--attach", "copier-lint-v1"] & TEE except ProcessExecutionError as error: - raise SystemExit(error.errno) + raise SystemExit(error.errno) from error diff --git a/pyproject.toml b/pyproject.toml index 32c1cc976..b2204eac1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,21 +109,33 @@ vcs = "git" extend-select = [ "ARG", "B", + "C4", "C90", "D", "E", "F", "FA", + "FLY", + "FURB", "I", + "ICN", + "ISC", + "N", "PERF", + "PIE", "PGH", "PTH", + "RET", + "RSE", + "RUF", + "SIM", "UP", ] -extend-ignore = ['B028', "B904", "D105", "D107", "E501"] +ignore = ["B028"] [tool.ruff.lint.per-file-ignores] -"tests/**" = ["D"] +"tests/**" = ["D100", "D101", "D102", "D103", "D104", "D107"] +"copier/errors.py" = ["D107"] [tool.ruff.lint.isort] combine-as-imports = true diff --git a/tests/conftest.py b/tests/conftest.py index 2d3d3e7b6..e1d30fe6e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -54,10 +54,10 @@ def default_git_user_email() -> Any: @pytest.fixture(scope="session", autouse=True) def default_gitconfig(default_gitconfig: GitConfig) -> GitConfig: - """ - Use a clean and isolated default gitconfig avoiding user settings to break some tests. + """Use a clean and isolated default gitconfig. - Add plumbum support to the original session-scoped fixture. + - Avoid user settings to break some tests. + - Add plumbum support to the original session-scoped fixture. """ # local.env is a snapshot frozen at Python startup requiring its own monkeypatching for var in list(local.env.keys()): @@ -70,8 +70,7 @@ def default_gitconfig(default_gitconfig: GitConfig) -> GitConfig: @pytest.fixture def gitconfig(gitconfig: GitConfig) -> Iterator[GitConfig]: - """ - Use a clean and isolated gitconfig to test some specific user settings. + """Use a clean and isolated gitconfig to test some specific user settings. Add plumbum support to the original function-scoped fixture. """ @@ -90,5 +89,4 @@ def config_path(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Iterator[Pat @pytest.fixture def settings_path(config_path: Path) -> Path: config_path.mkdir() - settings_path = config_path / "settings.yml" - return settings_path + return config_path / "settings.yml" diff --git a/tests/helpers.py b/tests/helpers.py index c50086b47..7576a9fff 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -131,7 +131,7 @@ def build_file_tree( def expect_prompt( tui: PopenSpawn, name: str, expected_type: str, help: str | None = None ) -> None: - """Check that we get a prompt in the standard form""" + """Check that we get a prompt in the standard form.""" if help: tui.expect_exact(help) else: diff --git a/tests/test_answersfile.py b/tests/test_answersfile.py index 7bf4d7cb5..e5b5904a6 100644 --- a/tests/test_answersfile.py +++ b/tests/test_answersfile.py @@ -155,7 +155,7 @@ def test_external_data(tmp_path_factory: pytest.TempPathFactory) -> None: parent2: "{{ parent2_answers }}" parent2_answers: .parent2-answers.yml name: "{{ _external_data.parent2.child | d(_external_data.parent1.child) }}" - """ + """ # noqa: E501 ), (child / "combined.json.jinja"): """\ { diff --git a/tests/test_answersfile_templating.py b/tests/test_answersfile_templating.py index 6a951b8df..640b52e82 100644 --- a/tests/test_answersfile_templating.py +++ b/tests/test_answersfile_templating.py @@ -34,8 +34,7 @@ def template_path(tmp_path_factory: pytest.TempPathFactory) -> str: def test_answersfile_templating( template_path: str, tmp_path: Path, answers_file: str | None ) -> None: - """ - Test copier behaves properly when _answers_file contains a template + """Test copier behaves properly when _answers_file contains a template. Checks that template is resolved successfully and that a subsequent copy that resolves to a different answers file doesn't clobber the diff --git a/tests/test_cli.py b/tests/test_cli.py index 8c6331a53..1fa886f82 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -239,7 +239,6 @@ def test_good_cli_run_dot_config( Added based on the discussion: https://github.com/copier-org/copier/discussions/859 """ - src = template_path_with_dot_config(str(config_folder)) with local.cwd(src): diff --git a/tests/test_complex_questions.py b/tests/test_complex_questions.py index 15f3ac7e3..7c4a4a3f3 100644 --- a/tests/test_complex_questions.py +++ b/tests/test_complex_questions.py @@ -126,7 +126,7 @@ def check_invalid( help: str | None = None, err: str = "Invalid input", ) -> None: - """Check that invalid input is reported correctly""" + """Check that invalid input is reported correctly.""" expect_prompt(tui, name, format, help) tui.sendline(invalid_value) tui.expect_exact(invalid_value) @@ -169,7 +169,7 @@ def test_api(template_path: str, tmp_path: Path) -> None: def test_cli_interactive(template_path: str, tmp_path: Path, spawn: Spawn) -> None: """Test copier correctly processes advanced questions and answers through CLI.""" - tui = spawn(COPIER_PATH + ("copy", template_path, str(tmp_path)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", template_path, str(tmp_path)), timeout=10) expect_prompt(tui, "love_me", "bool", help="I need to know it. Do you love me?") tui.send("y") expect_prompt(tui, "your_name", "str", help="Please tell me your name.") @@ -311,8 +311,8 @@ def test_cli_interatively_with_flag_data_and_type_casts( ) -> None: """Assert how choices work when copier is invoked with --data interactively.""" tui = spawn( - COPIER_PATH - + ( + ( + *COPIER_PATH, "copy", "--data=choose_list=second", "--data=choose_dict=first", @@ -406,7 +406,7 @@ def test_tui_inherited_default( git("add", "--all") git("commit", "--message", "init template") git("tag", "1") - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "owner1", "str") tui.sendline("example") expect_prompt(tui, "has_2_owners", "bool") @@ -465,7 +465,7 @@ def test_tui_typed_default( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) tui.expect_exact(pexpect.EOF) assert json.loads((dst / "answers.json").read_text()) == {"_src_path": str(src)} assert json.loads((dst / "context.json").read_text()) == { @@ -506,7 +506,7 @@ def test_selection_type_cast( (src / "answers.json.jinja"): "{{ _copier_answers|to_json }}", } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt( tui, "postgres1", "yaml", help="Which PostgreSQL version do you want to deploy?" ) diff --git a/tests/test_conditional_file_name.py b/tests/test_conditional_file_name.py index 599dc6ec0..fc499bbd6 100644 --- a/tests/test_conditional_file_name.py +++ b/tests/test_conditional_file_name.py @@ -69,7 +69,7 @@ def test_answer_changes( with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 "copier.yml": """ condition: type: bool @@ -83,7 +83,7 @@ def test_answer_changes( git("tag", "v1") if interactive: - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "condition", "bool") tui.expect_exact("(y/N)") tui.sendline("y") @@ -100,7 +100,7 @@ def test_answer_changes( git("commit", "-mv1") if interactive: - tui = spawn(COPIER_PATH + ("update", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "update", str(dst)), timeout=10) expect_prompt(tui, "condition", "bool") tui.expect_exact("(Y/n)") tui.sendline("n") diff --git a/tests/test_config.py b/tests/test_config.py index 53b2644d4..7b82776ad 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -340,7 +340,7 @@ def test_missing_template(tmp_path: Path) -> None: def is_subdict(small: dict[Any, Any], big: dict[Any, Any]) -> bool: - return {**big, **small} == big + return big == {**big, **small} def test_worker_good_data(tmp_path: Path) -> None: @@ -361,7 +361,7 @@ def test_worker_good_data(tmp_path: Path) -> None: # func_args > defaults ( {"src_path": ".", "exclude": ["aaa"]}, - tuple(DEFAULT_EXCLUDE) + ("aaa",), + (*DEFAULT_EXCLUDE, "aaa"), ), # func_args > user_data ( @@ -548,8 +548,8 @@ def test_user_defaults( """ ), ), - # User provided defaults takes precedence over initial defaults and settings defaults. - # The output should remain unchanged following the update operation. + # User provided defaults takes precedence over initial defaults and settings + # defaults. The output should remain unchanged following the update operation. ( { "a_string": "foo", diff --git a/tests/test_copy.py b/tests/test_copy.py index 8e442b8b1..deb1a3983 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -976,7 +976,7 @@ def test_multiselect_choices_preserve_order( ( """\ choices: '[{% for c in ["one", "two", "three"] %}{{ c }}{% if not loop.last %},{% endif %}{% endfor %}]' - """ + """ # noqa: E501 ), ( """\ @@ -1027,7 +1027,7 @@ def test_multiselect_choices_preserve_order( value: {{ c }} validator: "{% raw %}{% if false %}Validation error{% endif %}{% endraw %}" {%- endfor %} - """ + """ # noqa: E501 ), ], ) diff --git a/tests/test_dynamic_file_structures.py b/tests/test_dynamic_file_structures.py index f86bc8d52..d8b5c7aa2 100644 --- a/tests/test_dynamic_file_structures.py +++ b/tests/test_dynamic_file_structures.py @@ -51,7 +51,7 @@ def test_nested_folder_loop(tmp_path_factory: pytest.TempPathFactory) -> None: / "nested_folder_loop" / "{% yield string_item from strings %}{{ string_item }}{% endyield %}" / "{% yield integer_item from integers %}{{ integer_item }}{% endyield %}" - / "{{ string_item }}_{{ integer_item }}.txt.jinja": "Hello {{ string_item }} {{ integer_item }}", + / "{{ string_item }}_{{ integer_item }}.txt.jinja": "Hello {{ string_item }} {{ integer_item }}", # noqa: E501 } ) with warnings.catch_warnings(): @@ -90,7 +90,7 @@ def test_file_loop(tmp_path_factory: pytest.TempPathFactory) -> None: src / "copier.yml": "", src / "file_loop" - / "{% yield string_item from strings %}{{ string_item }}{% endyield %}.jinja": "Hello {{ string_item }}", + / "{% yield string_item from strings %}{{ string_item }}{% endyield %}.jinja": "Hello {{ string_item }}", # noqa: E501 } ) with warnings.catch_warnings(): @@ -128,8 +128,8 @@ def test_folder_loop_dict_items(tmp_path_factory: pytest.TempPathFactory) -> Non src / "copier.yml": "", src / "folder_loop_dict_items" - / "{% yield dict_item from dicts %}{{ dict_item.folder_name }}{% endyield %}" - / "{{ dict_item.file_name }}.txt.jinja": "Hello {{ '-'.join(dict_item.content) }}", + / "{% yield dict_item from dicts %}{{ dict_item.folder_name }}{% endyield %}" # noqa: E501 + / "{{ dict_item.file_name }}.txt.jinja": "Hello {{ '-'.join(dict_item.content) }}", # noqa: E501 } ) @@ -206,7 +206,7 @@ def test_raise_yield_tag_in_file(tmp_path_factory: pytest.TempPathFactory) -> No def test_raise_multiple_yield_tags(tmp_path_factory: pytest.TempPathFactory) -> None: src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) # multiple yield tags, not nested - file_name = "{% yield item1 from strings %}{{ item1 }}{% endyield %}{% yield item2 from strings %}{{ item2 }}{% endyield %}" + file_name = "{% yield item1 from strings %}{{ item1 }}{% endyield %}{% yield item2 from strings %}{{ item2 }}{% endyield %}" # noqa: E501 build_file_tree( { @@ -228,7 +228,7 @@ def test_raise_multiple_yield_tags(tmp_path_factory: pytest.TempPathFactory) -> src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) # multiple yield tags, nested - file_name = "{% yield item1 from strings %}{% yield item2 from strings %}{{ item1 }}{{ item2 }}{% endyield %}{% endyield %}" + file_name = "{% yield item1 from strings %}{% yield item2 from strings %}{{ item1 }}{{ item2 }}{% endyield %}{% endyield %}" # noqa: E501 build_file_tree( { diff --git a/tests/test_imports.py b/tests/test_imports.py index f193475f0..c2f714548 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -132,13 +132,13 @@ def test_import_macro( ( src / subdir - / "{% from pathjoin('includes', 'slugify.jinja') import slugify %}{{ slugify(name) }}.txt" + / "{% from pathjoin('includes', 'slugify.jinja') import slugify %}{{ slugify(name) }}.txt" # noqa: E501 ): "", # File for testing the Jinja import statement in the folder name. ( src / subdir - / "{% from pathjoin('includes', 'slugify.jinja') import slugify %}{{ slugify(name) }}" + / "{% from pathjoin('includes', 'slugify.jinja') import slugify %}{{ slugify(name) }}" # noqa: E501 / "test.txt" ): "", } diff --git a/tests/test_interrupts.py b/tests/test_interrupts.py index d9b17d071..e75372cbc 100644 --- a/tests/test_interrupts.py +++ b/tests/test_interrupts.py @@ -3,7 +3,7 @@ import pytest from copier import Worker -from copier.errors import CopierAnswersInterrupt +from copier.errors import CopierAnswersInterruptError from .helpers import build_file_tree @@ -14,7 +14,7 @@ # We override the prompt method from questionary to raise this # exception and expect our surrounding machinery to re-raise # it as a CopierAnswersInterrupt. - CopierAnswersInterrupt(Mock(), Mock(), Mock()), + CopierAnswersInterruptError(Mock(), Mock(), Mock()), KeyboardInterrupt, ], ) @@ -34,9 +34,10 @@ def test_keyboard_interrupt( ) worker = Worker(str(src), dst, defaults=False) - with patch("copier.main.unsafe_prompt", side_effect=side_effect): - with pytest.raises(KeyboardInterrupt): - worker.run_copy() + with patch("copier.main.unsafe_prompt", side_effect=side_effect), pytest.raises( + KeyboardInterrupt + ): + worker.run_copy() def test_multiple_questions_interrupt(tmp_path_factory: pytest.TempPathFactory) -> None: @@ -65,7 +66,7 @@ def test_multiple_questions_interrupt(tmp_path_factory: pytest.TempPathFactory) KeyboardInterrupt, ], ): - with pytest.raises(CopierAnswersInterrupt) as err: + with pytest.raises(CopierAnswersInterruptError) as err: worker.run_copy() assert err.value.answers.user == { "question1": "foobar", diff --git a/tests/test_legacy_migration.py b/tests/test_legacy_migration.py index 0a3ef79c1..791bf6893 100644 --- a/tests/test_legacy_migration.py +++ b/tests/test_legacy_migration.py @@ -173,7 +173,7 @@ def test_prereleases(tmp_path_factory: pytest.TempPathFactory) -> None: build_file_tree( { "version.txt": "v1.0.0", - "[[ _copier_conf.answers_file ]].jinja": "[[_copier_answers|to_nice_yaml]]", + "[[ _copier_conf.answers_file ]].jinja": "[[_copier_answers|to_nice_yaml]]", # noqa: E501 "copier.yaml": ( f"""\ _envops: {BRACKET_ENVOPS_JSON} @@ -193,7 +193,7 @@ def test_prereleases(tmp_path_factory: pytest.TempPathFactory) -> None: - version: v2.a2 before: - [python, -c, "import pathlib; pathlib.Path('v2.a2').touch()"] - """ + """ # noqa: E501 ), } ) @@ -263,7 +263,7 @@ def test_pretend_mode(tmp_path_factory: pytest.TempPathFactory) -> None: git("init") build_file_tree( { - "[[ _copier_conf.answers_file ]].jinja": "[[_copier_answers|to_nice_yaml]]", + "[[ _copier_conf.answers_file ]].jinja": "[[_copier_answers|to_nice_yaml]]", # noqa: E501 "copier.yml": ( f"""\ _envops: {BRACKET_ENVOPS_JSON} @@ -288,7 +288,7 @@ def test_pretend_mode(tmp_path_factory: pytest.TempPathFactory) -> None: with local.cwd(src): build_file_tree( { - "[[ _copier_conf.answers_file ]].jinja": "[[_copier_answers|to_nice_yaml]]", + "[[ _copier_conf.answers_file ]].jinja": "[[_copier_answers|to_nice_yaml]]", # noqa: E501 "copier.yml": ( f"""\ _envops: {BRACKET_ENVOPS_JSON} diff --git a/tests/test_migrations.py b/tests/test_migrations.py index b77f50d90..cb040a5eb 100644 --- a/tests/test_migrations.py +++ b/tests/test_migrations.py @@ -19,7 +19,7 @@ def test_basic_migration(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test a basic migration running on every version""" + """Test a basic migration running on every version.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): @@ -50,7 +50,7 @@ def test_basic_migration(tmp_path_factory: pytest.TempPathFactory) -> None: def test_requires_unsafe(tmp_path_factory: pytest.TempPathFactory) -> None: - """Tests that migrations require the unsafe flag to be passed""" + """Tests that migrations require the unsafe flag to be passed.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): @@ -74,15 +74,14 @@ def test_requires_unsafe(tmp_path_factory: pytest.TempPathFactory) -> None: with local.cwd(src): git("tag", "v2") - with local.cwd(dst): - with pytest.raises(UnsafeTemplateError): - run_update(defaults=True, overwrite=True, unsafe=False) + with local.cwd(dst), pytest.raises(UnsafeTemplateError): + run_update(defaults=True, overwrite=True, unsafe=False) assert not (dst / "foo").exists() def test_version_migration(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test a migration running on a specific version""" + """Test a migration running on a specific version.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): @@ -119,7 +118,7 @@ def test_version_migration(tmp_path_factory: pytest.TempPathFactory) -> None: def test_prerelease_version_migration(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test if prerelease version migrations work""" + """Test if prerelease version migrations work.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) versions = ["v2.dev0", "v2.dev2", "v2.a1", "v2.a2"] @@ -183,7 +182,7 @@ def test_prerelease_version_migration(tmp_path_factory: pytest.TempPathFactory) def test_migration_working_directory(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test the working directory attribute of migrations""" + """Test the working directory attribute of migrations.""" src, dst, workdir = map(tmp_path_factory.mktemp, ("src", "dst", "workdir")) with local.cwd(src): @@ -219,7 +218,7 @@ def test_migration_working_directory(tmp_path_factory: pytest.TempPathFactory) - def test_migration_condition( tmp_path_factory: pytest.TempPathFactory, condition: bool ) -> None: - """Test the `when` argument of migrations""" + """Test the `when` argument of migrations.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): @@ -251,7 +250,7 @@ def test_migration_condition( def test_pretend_migration(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test that migrations aren't run in pretend mode""" + """Test that migrations aren't run in pretend mode.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): @@ -282,7 +281,7 @@ def test_pretend_migration(tmp_path_factory: pytest.TempPathFactory) -> None: def test_skip_migration(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test that migrations aren't run in pretend mode""" + """Test that migrations aren't run in pretend mode.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): @@ -313,14 +312,15 @@ def test_skip_migration(tmp_path_factory: pytest.TempPathFactory) -> None: def test_migration_run_before(tmp_path_factory: pytest.TempPathFactory) -> None: - """Test running migrations in the before upgrade step""" + """Test running migrations in the before upgrade step.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree( { **COPIER_ANSWERS_FILE, - # We replace an answer in the before step, so it will be used during update + # We replace an answer in the before step, so it will be used during + # update "copier.yml": ( """ hello: @@ -364,8 +364,8 @@ def test_migration_run_before(tmp_path_factory: pytest.TempPathFactory) -> None: def test_migration_run_after( tmp_path_factory: pytest.TempPathFactory, explicit: bool ) -> None: - """ - Test running migrations in the before upgrade step + """Test running migrations in the before upgrade step. + Also checks that this is the default behaviour if no `when` is given. """ src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) @@ -404,7 +404,7 @@ def test_migration_run_after( def test_migration_env_variables( tmp_path_factory: pytest.TempPathFactory, with_version: bool ) -> None: - """Test that environment variables are passed to the migration commands""" + """Test that environment variables are passed to the migration commands.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) variables = { @@ -461,7 +461,7 @@ def test_migration_env_variables( def test_migration_jinja_variables( tmp_path_factory: pytest.TempPathFactory, with_version: bool ) -> None: - """Test that environment variables are passed to the migration commands""" + """Test that environment variables are passed to the migration commands.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) variables = { @@ -512,7 +512,7 @@ def test_migration_jinja_variables( assert (dst / "vars.txt").is_file() raw_vars = (dst / "vars.txt").read_text().split("\n") - vars = map(lambda x: x.strip(), raw_vars) + vars = {x.strip() for x in raw_vars} for variable, value in variables.items(): assert f"{variable}={value}" in vars diff --git a/tests/test_output.py b/tests/test_output.py index 069bad3e8..3f448542a 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -86,7 +86,10 @@ def test_answer_with_invalid_type(tmp_path_factory: pytest.TempPathFactory) -> N ) with pytest.raises( InvalidTypeError, - match='Invalid answer "None" of type "" to question "bad" of type "int"', + match=( + 'Invalid answer "None" of type "" to question "bad" of ' + 'type "int"' + ), ): run_copy(str(src), dst, defaults=True, overwrite=True) @@ -111,7 +114,7 @@ def test_messages_with_inline_text( _message_after_copy: Project {{ project_name }} successfully created _message_before_update: Updating on {{ _copier_conf.os }} _message_after_update: Project {{ project_name }} successfully updated - """ + """ # noqa: E501 ), (src / "{{ _copier_conf.answers_file }}.jinja"): ( """\ @@ -143,7 +146,7 @@ def test_messages_with_inline_text( # copy if interactive: - tui = spawn(COPIER_PATH + ("copy", "-r", "v1", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", "-r", "v1", str(src), str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("myproj") tui.expect_exact(pexpect.EOF) @@ -158,12 +161,12 @@ def test_messages_with_inline_text( Project\ myproj\ successfully\ created\s*$ """, err, - flags=re.S | re.X, + flags=re.DOTALL | re.VERBOSE, ) # recopy if interactive: - tui = spawn(COPIER_PATH + ("recopy", "-r", "v1", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "recopy", "-r", "v1", str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("_new") tui.expect_exact(pexpect.EOF) @@ -178,7 +181,7 @@ def test_messages_with_inline_text( Project\ myproj_new\ successfully\ created\s*$ """, err, - flags=re.S | re.X, + flags=re.DOTALL | re.VERBOSE, ) with local.cwd(dst): @@ -191,7 +194,7 @@ def test_messages_with_inline_text( # update if interactive: - tui = spawn(COPIER_PATH + ("update", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "update", str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("_update") tui.expect_exact(pexpect.EOF) @@ -206,7 +209,7 @@ def test_messages_with_inline_text( Project\ myproj_new_update\ successfully\ updated\s*$ """, err, - flags=re.S | re.X, + flags=re.DOTALL | re.VERBOSE, ) @@ -283,7 +286,7 @@ def test_messages_with_included_text( # copy if interactive: - tui = spawn(COPIER_PATH + ("copy", "-r", "v1", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", "-r", "v1", str(src), str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("myproj") tui.expect_exact(pexpect.EOF) @@ -298,12 +301,12 @@ def test_messages_with_included_text( Project\ myproj\ successfully\ created\s*$ """, err, - flags=re.S | re.X, + flags=re.DOTALL | re.VERBOSE, ) # recopy if interactive: - tui = spawn(COPIER_PATH + ("recopy", "-r", "v1", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "recopy", "-r", "v1", str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("_new") tui.expect_exact(pexpect.EOF) @@ -318,7 +321,7 @@ def test_messages_with_included_text( Project\ myproj_new\ successfully\ created\s*$ """, err, - flags=re.S | re.X, + flags=re.DOTALL | re.VERBOSE, ) with local.cwd(dst): @@ -331,7 +334,7 @@ def test_messages_with_included_text( # update if interactive: - tui = spawn(COPIER_PATH + ("update", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "update", str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("_update") tui.expect_exact(pexpect.EOF) @@ -346,7 +349,7 @@ def test_messages_with_included_text( Project\ myproj_new_update\ successfully\ updated\s*$ """, err, - flags=re.S | re.X, + flags=re.DOTALL | re.VERBOSE, ) @@ -370,7 +373,7 @@ def test_messages_quiet( _message_after_copy: Project {{ project_name }} successfully created _message_before_update: Updating on {{ _copier_conf.os }} _message_after_update: Project {{ project_name }} successfully updated - """ + """ # noqa: E501 ), (src / "{{ _copier_conf.answers_file }}.jinja"): ( """\ @@ -403,7 +406,7 @@ def test_messages_quiet( # copy if interactive: tui = spawn( - COPIER_PATH + ("copy", "--quiet", "-r", "v1", str(src), str(dst)), + (*COPIER_PATH, "copy", "--quiet", "-r", "v1", str(src), str(dst)), timeout=10, ) expect_prompt(tui, "project_name", "str") @@ -422,7 +425,7 @@ def test_messages_quiet( # recopy if interactive: tui = spawn( - COPIER_PATH + ("recopy", "--quiet", "-r", "v1", str(dst)), timeout=10 + (*COPIER_PATH, "recopy", "--quiet", "-r", "v1", str(dst)), timeout=10 ) expect_prompt(tui, "project_name", "str") tui.sendline("_new") @@ -445,7 +448,7 @@ def test_messages_quiet( # update if interactive: - tui = spawn(COPIER_PATH + ("update", "--quiet", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "update", "--quiet", str(dst)), timeout=10) expect_prompt(tui, "project_name", "str") tui.sendline("_update") tui.expect_exact(pexpect.EOF) diff --git a/tests/test_prompt.py b/tests/test_prompt.py index 1034e55f6..6775b29d7 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -100,7 +100,7 @@ def test_copy_default_advertised( name: str, args: tuple[str, ...], ) -> None: - """Test that the questions for the user are OK""" + """Test that the questions for the user are OK.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree(MARIO_TREE) @@ -110,7 +110,7 @@ def test_copy_default_advertised( with local.cwd(dst): # Copy the v1 template tui = spawn( - COPIER_PATH + ("copy", str(src), ".", "--vcs-ref=v1") + args, timeout=10 + (*COPIER_PATH, "copy", str(src), ".", "--vcs-ref=v1", *args), timeout=10 ) # Check what was captured expect_prompt(tui, "in_love", "bool") @@ -134,7 +134,7 @@ def test_copy_default_advertised( # Update subproject git_save() assert "_commit: v1" in Path(".copier-answers.yml").read_text() - tui = spawn(COPIER_PATH + ("update",), timeout=30) + tui = spawn((*COPIER_PATH, "update"), timeout=30) # Check what was captured expect_prompt(tui, "in_love", "bool") tui.expect_exact("(Y/n)") @@ -168,7 +168,7 @@ def test_update_skip_answered( update_action: str, args: tuple[str, ...], ) -> None: - """Test that the questions for the user are OK""" + """Test that the questions for the user are OK.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree(MARIO_TREE) @@ -178,7 +178,7 @@ def test_update_skip_answered( with local.cwd(dst): # Copy the v1 template tui = spawn( - COPIER_PATH + ("copy", str(src), ".", "--vcs-ref=v1") + args, timeout=10 + (*COPIER_PATH, "copy", str(src), ".", "--vcs-ref=v1", *args), timeout=10 ) # Check what was captured expect_prompt(tui, "in_love", "bool") @@ -202,8 +202,8 @@ def test_update_skip_answered( # Update subproject git_save() tui = spawn( - COPIER_PATH - + ( + ( + *COPIER_PATH, update_action, "--skip-answered", ), @@ -231,7 +231,7 @@ def test_update_with_new_field_in_new_version_skip_answered( name: str, args: tuple[str, ...], ) -> None: - """Test that the questions for the user are OK""" + """Test that the questions for the user are OK.""" src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree(MARIO_TREE) @@ -241,7 +241,7 @@ def test_update_with_new_field_in_new_version_skip_answered( with local.cwd(dst): # Copy the v1 template tui = spawn( - COPIER_PATH + ("copy", str(src), ".", "--vcs-ref=v1") + args, timeout=10 + (*COPIER_PATH, "copy", str(src), ".", "--vcs-ref=v1", *args), timeout=10 ) # Check what was captured expect_prompt(tui, "in_love", "bool") @@ -265,8 +265,8 @@ def test_update_with_new_field_in_new_version_skip_answered( # Update subproject git_save() tui = spawn( - COPIER_PATH - + ( + ( + *COPIER_PATH, "update", "-A", ), @@ -356,7 +356,7 @@ def test_when( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question_1", type(question_1).__name__) tui.sendline() if asks: @@ -385,7 +385,7 @@ def test_placeholder(tmp_path_factory: pytest.TempPathFactory, spawn: Spawn) -> "question_2": { "type": "str", "help": "write a list of answers", - "placeholder": "Write something like [[ question_1 ]], but better", + "placeholder": "Write something like [[ question_1 ]], but better", # noqa: E501 }, } ), @@ -394,7 +394,7 @@ def test_placeholder(tmp_path_factory: pytest.TempPathFactory, spawn: Spawn) -> ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question_1", "str") tui.expect_exact("answer 1") tui.sendline() @@ -439,7 +439,7 @@ def test_multiline( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question_1", "str") tui.expect_exact("answer 1") tui.sendline() @@ -514,7 +514,7 @@ def test_update_choice( git("commit", "-m one") git("tag", "v1") # Copy - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "pick_one", "float") tui.sendline(Keyboard.Up) tui.expect_exact(pexpect.EOF) @@ -526,8 +526,8 @@ def test_update_choice( git("commit", "-m1") # Update tui = spawn( - COPIER_PATH - + ( + ( + *COPIER_PATH, "update", str(dst), ), @@ -575,7 +575,7 @@ def test_multiline_defaults( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "yaml_single", "yaml") # This test will always fail here, because python prompt toolkit gives # syntax highlighting to YAML and JSON outputs, encoded into terminal @@ -591,7 +591,7 @@ def test_multiline_defaults( tui.send(Keyboard.Enter) expect_prompt(tui, "json_multi", "json") tui.expect_exact( - '> [\n "one",\n "two",\n {\n "three": [\n "four"\n ]\n }\n ]' + '> [\n "one",\n "two",\n {\n "three": [\n "four"\n ]\n }\n ]' # noqa: E501 ) tui.send(Keyboard.Alt + Keyboard.Enter) tui.expect_exact(pexpect.EOF) @@ -620,7 +620,7 @@ def test_partial_interrupt( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question_1", "str") tui.expect_exact("answer 1") # Answer the first question using the default. @@ -660,7 +660,7 @@ def test_var_name_value_allowed( } ) # Copy - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "value", "str") tui.expect_exact("string") tui.send(Keyboard.Alt + Keyboard.Enter) @@ -701,7 +701,7 @@ def test_required_text_question( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question", type_name) tui.expect_exact("") tui.sendline() @@ -735,7 +735,7 @@ def test_required_bool_question( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question", "bool") tui.expect_exact("(y/N)") tui.sendline() @@ -782,7 +782,7 @@ def test_required_choice_question( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "question", type_name) tui.sendline() tui.expect_exact(pexpect.EOF) diff --git a/tests/test_recopy.py b/tests/test_recopy.py index f7460c8ec..f6e048143 100644 --- a/tests/test_recopy.py +++ b/tests/test_recopy.py @@ -20,7 +20,7 @@ def tpl(tmp_path_factory: pytest.TempPathFactory) -> str: build_file_tree( { "copier.yml": "your_name: Mario", - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 "name.txt.jinja": "This is your name: {{ your_name }}.", } ) diff --git a/tests/test_subdirectory.py b/tests/test_subdirectory.py index 5a3393bdb..324b47cb0 100644 --- a/tests/test_subdirectory.py +++ b/tests/test_subdirectory.py @@ -128,7 +128,7 @@ def test_update_subdirectory_from_root_path( bye """ ), - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 } ) git("init") diff --git a/tests/test_templated_prompt.py b/tests/test_templated_prompt.py index d7e745dc0..f51c20c97 100644 --- a/tests/test_templated_prompt.py +++ b/tests/test_templated_prompt.py @@ -170,7 +170,7 @@ def test_templated_prompt( ), } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "main", "str") tui.expect_exact(main_default) tui.sendline() @@ -208,7 +208,7 @@ def test_templated_prompt_custom_envops( sentence: type: str default: "<% if powerlevel >= 9000 %>It's over 9000!<% else %>It's only << powerlevel >>...<% endif %>" - """ + """ # noqa: E501 ), (src / "result.jinja"): "<>", } @@ -354,12 +354,12 @@ def test_templated_prompt_with_conditional_choices( Deployment Manager: value: dm validator: "{% if cloud != 'GCP' %}Requires GCP{% endif %}" - """ + """ # noqa: E501 ), } ) tui = spawn( - COPIER_PATH + ("copy", f"--data=cloud={cloud}", str(src), str(dst)), + (*COPIER_PATH, "copy", f"--data=cloud={cloud}", str(src), str(dst)), timeout=10, ) expect_prompt(tui, "iac", "str", help="Which IaC tool do you use?") @@ -416,7 +416,7 @@ def test_templated_prompt_with_templated_choices( } ) tui = spawn( - COPIER_PATH + ("copy", f"--data=cloud={cloud}", str(src), str(dst)), + (*COPIER_PATH, "copy", f"--data=cloud={cloud}", str(src), str(dst)), timeout=10, ) expect_prompt(tui, "iac", "str", help="Which IaC tool do you use?") @@ -455,7 +455,7 @@ def test_templated_prompt_update_previous_answer_disabled( Deployment Manager: value: dm validator: "{% if cloud != 'GCP' %}Requires GCP{% endif %}" - """ + """ # noqa: E501 ), (src / "{{ _copier_conf.answers_file }}.jinja"): ( "{{ _copier_answers|to_nice_yaml }}" @@ -467,7 +467,7 @@ def test_templated_prompt_update_previous_answer_disabled( git_init("v1") git("tag", "v1") - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt(tui, "cloud", "str", help="Which cloud provider do you use?") tui.sendline(Keyboard.Down) # select "AWS" expect_prompt(tui, "iac", "str", help="Which IaC tool do you use?") @@ -487,7 +487,7 @@ def test_templated_prompt_update_previous_answer_disabled( with local.cwd(dst): git_init("v1") - tui = spawn(COPIER_PATH + ("update", str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "update", str(dst)), timeout=10) expect_prompt(tui, "cloud", "str", help="Which cloud provider do you use?") tui.sendline(Keyboard.Down) # select "Azure" expect_prompt(tui, "iac", "str", help="Which IaC tool do you use?") @@ -534,7 +534,7 @@ def test_multiselect_choices_with_templated_default_value( - "3.10" - "3.11" - "3.12" - """ + """ # noqa: E501 ), (src / "{{ _copier_conf.answers_file }}.jinja"): ( "{{ _copier_answers|to_nice_yaml }}" @@ -542,7 +542,7 @@ def test_multiselect_choices_with_templated_default_value( } ) - tui = spawn(COPIER_PATH + ("copy", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", str(src), str(dst)), timeout=10) expect_prompt( tui, "python_version", "str", help="What version of python are you targeting?" ) diff --git a/tests/test_tmpdir.py b/tests/test_tmpdir.py index 07fe621b3..20ad68416 100644 --- a/tests/test_tmpdir.py +++ b/tests/test_tmpdir.py @@ -17,7 +17,7 @@ def template_path(tmp_path_factory: pytest.TempPathFactory) -> str: root / "copier.yml": "favorite_app: Copier", root / "fav.txt.jinja": "{{ favorite_app }}", root - / "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + / "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 } ) _git = git["-C", root] diff --git a/tests/test_tools.py b/tests/test_tools.py index 0bc6794ba..a02ef1bc9 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -17,7 +17,10 @@ def test_types() -> None: def test_temporary_directory_with_readonly_files_deletion() -> None: - """Ensure temporary directories containing read-only files are properly deleted, whatever the OS.""" + """Ensure temporary directories containing read-only files are properly deleted. + + Works regardless of the OS. + """ with TemporaryDirectory() as tmp_dir: ro_file = Path(tmp_dir) / "readonly.txt" with ro_file.open("w") as fp: @@ -27,7 +30,10 @@ def test_temporary_directory_with_readonly_files_deletion() -> None: def test_temporary_directory_with_git_repo_deletion() -> None: - """Ensure temporary directories containing git repositories are properly deleted, whatever the OS.""" + """Ensure temporary directories containing git repositories are properly deleted. + + Works regardless of the OS. + """ with TemporaryDirectory() as tmp_dir: git("init") assert not Path(tmp_dir).exists() diff --git a/tests/test_unsafe.py b/tests/test_unsafe.py index e194a19a5..ab4947c94 100644 --- a/tests/test_unsafe.py +++ b/tests/test_unsafe.py @@ -72,7 +72,10 @@ class JinjaExtension(Extension): ... }, pytest.raises( UnsafeTemplateError, - match="Template uses potentially unsafe features: jinja_extensions, tasks.", + match=( + "Template uses potentially unsafe features: " + "jinja_extensions, tasks." + ), ), ), ], @@ -297,7 +300,7 @@ def test_update( with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers | to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers | to_nice_yaml }}", # noqa: E501 "copier.yaml": yaml.safe_dump(spec_old), } ) @@ -343,7 +346,7 @@ def test_update_cli( with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers | to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers | to_nice_yaml }}", # noqa: E501 "copier.yaml": "", } ) @@ -356,7 +359,7 @@ def test_update_cli( settings_path.write_text(f"trust: ['{src}']") _, retcode = CopierApp.run( - ["copier", "copy", str(src), str(dst)] + unsafe_args, + ["copier", "copy", str(src), str(dst), *unsafe_args], exit=False, ) assert retcode == 0 @@ -383,8 +386,8 @@ def test_update_cli( "copier", "update", str(dst), - ] - + unsafe_args, + *unsafe_args, + ], exit=False, ) if unsafe or trusted_from_settings: diff --git a/tests/test_updatediff.py b/tests/test_updatediff.py index d85522104..a2f3d5ebb 100644 --- a/tests/test_updatediff.py +++ b/tests/test_updatediff.py @@ -488,7 +488,7 @@ def test_update_from_tagged_to_head(tmp_path_factory: pytest.TempPathFactory) -> with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 "example": "1", } ) @@ -524,7 +524,7 @@ def test_skip_update(tmp_path_factory: pytest.TempPathFactory) -> None: build_file_tree( { "copier.yaml": "_skip_if_exists: [skip_me]", - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "skip_me": "1", } ) @@ -602,9 +602,10 @@ def test_skip_update(tmp_path_factory: pytest.TempPathFactory) -> None: def test_skip_update_deleted( file_name: str, tmp_path_factory: pytest.TempPathFactory ) -> None: - """ - Ensure that paths in ``skip_if_exists`` are always recreated - if they are absent before updating. + """Ensure paths in ``skip_if_exists`` are recreated if absent. + + This ensures that paths specified in ``skip_if_exists`` are always recreated if they + are absent before updating. """ src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) @@ -612,7 +613,7 @@ def test_skip_update_deleted( build_file_tree( { "copier.yaml": "_skip_if_exists: ['*skip*']", - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 file_name: "1", "another_file": "foobar", } @@ -701,15 +702,15 @@ def test_skip_update_deleted( def test_update_deleted_path( file_name: str, tmp_path_factory: pytest.TempPathFactory ) -> None: - """ - Ensure that deleted paths are not regenerated during updates, - even if the template has changes in that path. + """Ensure that deleted paths are not regenerated during updates. + + Even if the template has changes in that path. """ src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 file_name: "foo", "another_file": "foobar", "dont_wildmatch": "bar", @@ -753,7 +754,7 @@ def test_overwrite_answers_file_always( build_file_tree( { "copier.yaml": "question_1: true", - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "answer_1.jinja": "{{ question_1 }}", } ) @@ -787,7 +788,7 @@ def test_file_removed(tmp_path_factory: pytest.TempPathFactory) -> None: with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "1.txt": "content 1", Path("dir 2", "2.txt"): "content 2", Path("dir 3", "subdir 3", "3.txt"): "content 3", @@ -872,7 +873,7 @@ def test_update_inline_changed_answers_and_questions( with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "copier.yml": "b: false", "content.jinja": """\ aaa @@ -911,7 +912,7 @@ def test_update_inline_changed_answers_and_questions( git("tag", "2") # Init project if interactive: - tui = spawn(COPIER_PATH + ("copy", "-r1", str(src), str(dst)), timeout=10) + tui = spawn((*COPIER_PATH, "copy", "-r1", str(src), str(dst)), timeout=10) tui.expect_exact("b (bool)") tui.expect_exact("(y/N)") tui.send("y") @@ -937,7 +938,7 @@ def test_update_inline_changed_answers_and_questions( git("commit", "-am2") # Update from template, inline, with answer changes if interactive: - tui = spawn(COPIER_PATH + ("update", "--conflict=inline"), timeout=10) + tui = spawn((*COPIER_PATH, "update", "--conflict=inline"), timeout=10) tui.expect_exact("b (bool)") tui.expect_exact("(Y/n)") tui.sendline() @@ -973,7 +974,7 @@ def test_update_in_repo_subdirectory( with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "version.txt": "v1", } ) @@ -1054,7 +1055,7 @@ def test_update_needs_more_context( with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "sample.py": dedent( """\ def function_one(): @@ -1486,7 +1487,7 @@ def test_update_with_new_file_in_template_and_project_via_migration( - version: v2 before: - "{{ _copier_python }} {{ _copier_conf.src_path / 'migrate.py' }}" - """ + """ # noqa: E501 ), "migrate.py": ( """\ @@ -1555,7 +1556,7 @@ def test_update_with_separate_git_directory( build_file_tree( { "version.txt": "v1", - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 } ) git("init") @@ -1595,7 +1596,7 @@ def test_update_with_skip_answered_and_new_answer( build_file_tree( { "copier.yml": "boolean: false", - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 } ) git_init("v1") @@ -1631,7 +1632,7 @@ def test_update_dont_validate_computed_value( validator: "This validator should never be rendered" """ ), - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 } ) git("init") @@ -1660,7 +1661,7 @@ def test_update_git_submodule(tmp_path_factory: pytest.TempPathFactory) -> None: with local.cwd(src): build_file_tree( { - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_yaml }}", # noqa: E501 "version.txt": "v1", } ) @@ -1784,7 +1785,7 @@ def test_update_with_answers_with_umlaut( type: str """ ), - "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", + "{{ _copier_conf.answers_file }}.jinja": "{{ _copier_answers|to_nice_yaml }}", # noqa: E501 } ) git_init("v1") diff --git a/tests/test_vcs.py b/tests/test_vcs.py index 5eba8d898..9648bd54d 100644 --- a/tests/test_vcs.py +++ b/tests/test_vcs.py @@ -88,8 +88,8 @@ def test_local_clone() -> None: @pytest.mark.impure def test_shallow_clone(tmp_path: Path, recwarn: pytest.WarningsRecorder) -> None: - # This test should always work but should be much slower if `is_git_shallow_repo()` is not - # checked in `clone()`. + # This test should always work but should be much slower if `is_git_shallow_repo()` + # is not checked in `clone()`. src_path = str(tmp_path / "autopretty") git("clone", "--depth=2", "https://github.com/copier-org/autopretty.git", src_path) assert Path(src_path, "README.md").exists() @@ -136,8 +136,8 @@ def test_update_using_local_source_path_with_tilde(tmp_path: Path) -> None: # then prepare the user path to this clone (starting with ~) if os.name == "nt": - # in GitHub CI, the user in the temporary path is not the same as the current user: - # ["C:\\", "Users", "RUNNER~X"] vs. runneradmin + # in GitHub CI, the user in the temporary path is not the same as the current + # user: ["C:\\", "Users", "RUNNER~X"] vs. runneradmin user = Path(src_path).parts[2] user_src_path = str(Path("~", "..", user, *Path(src_path).parts[3:])) else: