Skip to content

Commit 7e8cc2a

Browse files
committed
chore: fix Ruff linter errors
1 parent de960d0 commit 7e8cc2a

11 files changed

Lines changed: 54 additions & 41 deletions

copier/_jinja_ext.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from collections.abc import Callable, Iterable
66
from dataclasses import dataclass
77
from pathlib import PurePath
8-
from typing import Any
8+
from typing import Any, ClassVar
99
from weakref import WeakKeyDictionary
1010

1111
from jinja2 import Environment, nodes
@@ -94,7 +94,7 @@ class YieldExtension(Extension):
9494
```
9595
"""
9696

97-
tags = {"yield"}
97+
tags: ClassVar[set[str]] = {"yield"}
9898

9999
def preprocess(
100100
self, source: str, name: str | None, filename: str | None = None

copier/_main.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@
8383
YieldTagInFileError,
8484
)
8585

86+
if sys.version_info < (3, 11):
87+
from typing_extensions import Self
88+
else:
89+
from typing import Self
90+
8691
_T = TypeVar("_T")
8792
_P = ParamSpec("_P")
8893

@@ -262,7 +267,7 @@ class Worker:
262267
answers: AnswersMap = field(default_factory=AnswersMap, init=False)
263268
_cleanup_hooks: list[Callable[[], None]] = field(default_factory=list, init=False)
264269

265-
def __enter__(self) -> Worker:
270+
def __enter__(self) -> Self:
266271
"""Allow using worker as a context manager."""
267272
return self
268273

@@ -427,7 +432,9 @@ def _execute_tasks(self, tasks: Sequence[Task]) -> None:
427432

428433
extra_env = {k[1:].upper(): str(v) for k, v in extra_context.items()}
429434
with local.cwd(working_directory), local.env(**extra_env):
430-
process = subprocess.run(task_cmd, shell=use_shell, env=dict(local.env))
435+
process = subprocess.run(
436+
task_cmd, shell=use_shell, check=False, env=dict(local.env)
437+
)
431438
if process.returncode:
432439
raise TaskError.from_process(process)
433440

@@ -613,7 +620,7 @@ def _ask(self) -> None: # noqa: C901
613620
try:
614621
answer = question.parse_answer(self.answers.last[var_name])
615622
question.validate_answer(answer)
616-
except Exception:
623+
except Exception: # noqa: BLE001
617624
del self.answers.last[var_name]
618625
# Skip a question when the skip condition is met.
619626
if not question.get_when():
@@ -1062,7 +1069,7 @@ def _render_parts( # noqa: C901
10621069
context pairs.
10631070
"""
10641071
if rendered_parts is None:
1065-
rendered_parts = tuple()
1072+
rendered_parts = ()
10661073

10671074
if not parts:
10681075
rendered_path = Path(*rendered_parts)

copier/_template.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class _Loader(yaml.SafeLoader):
9494

9595
def _include(loader: yaml.Loader, node: yaml.Node) -> Any:
9696
if not isinstance(node, yaml.ScalarNode):
97-
raise ValueError(f"Unsupported YAML node: {node!r}")
97+
raise TypeError(f"Unsupported YAML node: {node!r}")
9898
include_file = str(loader.construct_scalar(node))
9999
if PurePosixPath(include_file).is_absolute():
100100
raise ValueError("YAML include file path must be a relative path")

copier/_tools.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from importlib.metadata import version
1616
from pathlib import Path
1717
from types import TracebackType
18-
from typing import Any, Literal, TextIO, TypeVar, cast
18+
from typing import Any, ClassVar, Literal, TextIO, TypeVar, cast
1919

2020
import colorama
2121
from packaging.version import Version
@@ -28,11 +28,11 @@
2828
class Style:
2929
"""Common color styles."""
3030

31-
OK = [colorama.Fore.GREEN, colorama.Style.BRIGHT]
32-
WARNING = [colorama.Fore.YELLOW, colorama.Style.BRIGHT]
33-
IGNORE = [colorama.Fore.CYAN]
34-
DANGER = [colorama.Fore.RED, colorama.Style.BRIGHT]
35-
RESET = [colorama.Fore.RESET, colorama.Style.RESET_ALL]
31+
OK: ClassVar[list[str]] = [colorama.Fore.GREEN, colorama.Style.BRIGHT]
32+
WARNING: ClassVar[list[str]] = [colorama.Fore.YELLOW, colorama.Style.BRIGHT]
33+
IGNORE: ClassVar[list[str]] = [colorama.Fore.CYAN]
34+
DANGER: ClassVar[list[str]] = [colorama.Fore.RED, colorama.Style.BRIGHT]
35+
RESET: ClassVar[list[str]] = [colorama.Fore.RESET, colorama.Style.RESET_ALL]
3636

3737

3838
INDENT = " " * 2
@@ -175,7 +175,7 @@ def handle_remove_readonly(
175175
Path(path).chmod(stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
176176
func(path)
177177
else:
178-
raise
178+
raise exc
179179

180180

181181
_re_whitespace = re.compile(r"^\s+|\s+$")

copier/_user_data.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from collections.abc import Callable, Mapping, Sequence
99
from copy import deepcopy
1010
from dataclasses import field
11-
from datetime import datetime
11+
from datetime import datetime, timezone
1212
from functools import cached_property
1313
from hashlib import sha512
1414
from os import urandom
@@ -47,7 +47,7 @@ def _now() -> datetime:
4747
"strftime format reference https://strftime.org/",
4848
FutureWarning,
4949
)
50-
return datetime.utcnow()
50+
return datetime.now(tz=timezone.utc())
5151

5252

5353
def _make_secret() -> str:
@@ -368,9 +368,8 @@ def _formatted_choices(self) -> Sequence[Choice]:
368368

369369
def get_message(self) -> str:
370370
"""Get the message that will be printed to the user."""
371-
if self.help:
372-
if rendered_help := self.render_value(self.help):
373-
return force_str_end(rendered_help) + " "
371+
if self.help and (rendered_help := self.render_value(self.help)):
372+
return force_str_end(rendered_help) + " "
374373
# Otherwise, there's no help message defined.
375374
message = self.var_name
376375
if (answer_type := self.get_type_name()) != "str":
@@ -387,11 +386,11 @@ def get_questionary_structure(self) -> AnyByStrDict: # noqa: C901
387386
def _validate(answer: str) -> str | Literal[True]:
388387
try:
389388
ans = self.parse_answer(answer)
390-
except Exception:
389+
except Exception: # noqa: BLE001
391390
return "Invalid input"
392391
try:
393392
self.validate_answer(ans)
394-
except Exception as exc:
393+
except Exception as exc: # noqa: BLE001
395394
return str(exc)
396395
return True
397396

@@ -460,7 +459,7 @@ def validate_answer(self, answer: Any) -> None:
460459
"""Validate user answer."""
461460
try:
462461
err_msg = self.render_value(self.validator, {self.var_name: answer}).strip()
463-
except Exception as error:
462+
except Exception as error: # noqa: BLE001
464463
err_msg = str(error)
465464
if err_msg:
466465
raise ValueError(
@@ -557,12 +556,12 @@ def parse_yaml_list(string: str) -> list[str]:
557556
The parsed list of raw items.
558557
559558
Raises:
560-
ValueError: If the YAML string is not a list.
559+
TypeError: If the YAML string is not a list.
561560
"""
562561
node = yaml.compose(string, Loader=yaml.SafeLoader)
563562

564563
if not isinstance(node, yaml.nodes.SequenceNode):
565-
raise ValueError(f"Not a YAML list: {string!r}")
564+
raise TypeError(f"Not a YAML list: {string!r}")
566565

567566
items = []
568567
for item in node.value:
@@ -571,12 +570,13 @@ def parse_yaml_list(string: str) -> list[str]:
571570
if (
572571
isinstance(item, yaml.nodes.ScalarNode)
573572
and item.tag == "tag:yaml.org,2002:str"
574-
):
575573
# Strip quotes if the value is quoted to avoid double-quoting.
576-
if (raw.startswith('"') and raw.endswith('"')) or (
577-
raw.startswith("'") and raw.endswith("'")
578-
):
579-
raw = raw[1:-1]
574+
and (
575+
(raw.startswith('"') and raw.endswith('"'))
576+
or (raw.startswith("'") and raw.endswith("'"))
577+
)
578+
):
579+
raw = raw[1:-1]
580580

581581
items.append(raw)
582582

copier/_vcs.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,12 @@ def is_git_bundle(path: Path) -> bool:
116116
"""Indicate if a path is a valid git bundle."""
117117
with suppress(OSError):
118118
path = path.resolve()
119-
with TemporaryDirectory(prefix=f"{__name__}.is_git_bundle.") as dirname:
120-
with local.cwd(dirname):
121-
get_git()("init")
122-
return bool(get_git()["bundle", "verify", path] & TF)
119+
with (
120+
TemporaryDirectory(prefix=f"{__name__}.is_git_bundle.") as dirname,
121+
local.cwd(dirname),
122+
):
123+
get_git()("init")
124+
return bool(get_git()["bundle", "verify", path] & TF)
123125

124126

125127
def get_repo(url: str) -> str | None:
@@ -145,7 +147,7 @@ def get_repo(url: str) -> str | None:
145147
if url.startswith("git+"):
146148
return url[4:]
147149
if url.startswith("https://") and not url.endswith(GIT_POSTFIX):
148-
return "".join((url, GIT_POSTFIX))
150+
return f"{url}{GIT_POSTFIX}"
149151
return url
150152

151153
url_path = Path(url)

tests/test_copy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ def test_value_with_forward_slash(tmp_path_factory: pytest.TempPathFactory) -> N
511511
({"type": "str"}, 1.1, does_not_raise()),
512512
({"type": "str"}, True, does_not_raise()),
513513
({"type": "str"}, False, does_not_raise()),
514-
({"type": "str"}, Decimal(1.1), does_not_raise()),
514+
({"type": "str"}, Decimal("1.1"), does_not_raise()),
515515
({"type": "str"}, Enum("A", ["a", "b"], type=str).a, does_not_raise()), # type: ignore[attr-defined]
516516
({"type": "str"}, Enum("A", ["a", "b"]).a, pytest.raises(ValueError)), # type: ignore[attr-defined]
517517
({"type": "str"}, object(), pytest.raises(ValueError)),

tests/test_interrupts.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ def test_keyboard_interrupt(
3434
)
3535
worker = Worker(str(src), dst, defaults=False)
3636

37-
with patch("copier._main.unsafe_prompt", side_effect=side_effect):
38-
with pytest.raises(KeyboardInterrupt):
39-
worker.run_copy()
37+
with (
38+
patch("copier._main.unsafe_prompt", side_effect=side_effect),
39+
pytest.raises(KeyboardInterrupt),
40+
):
41+
worker.run_copy()
4042

4143

4244
def test_multiple_questions_interrupt(tmp_path_factory: pytest.TempPathFactory) -> None:

tests/test_migrations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ def test_migration_jinja_variables(
567567

568568
assert (dst / "vars.txt").is_file()
569569
raw_vars = (dst / "vars.txt").read_text().split("\n")
570-
vars = map(lambda x: x.strip(), raw_vars)
570+
vars = {v.strip() for v in raw_vars}
571571
for variable, value in variables.items():
572572
assert f"{variable}={value}" in vars
573573

tests/test_prompt.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,7 @@ def test_interactive_session_required_for_question_prompt(
11691169
stdin=subprocess.PIPE, # Prevents interactive input
11701170
capture_output=True,
11711171
timeout=spawn_timeout or None,
1172+
check=False,
11721173
)
11731174
assert process.returncode == 1
11741175
assert (
@@ -1197,6 +1198,7 @@ def test_interactive_session_required_for_overwrite_prompt(
11971198
stdin=subprocess.PIPE, # Prevents interactive input
11981199
capture_output=True,
11991200
timeout=spawn_timeout or None,
1201+
check=False,
12001202
)
12011203
assert process.returncode == 1
12021204
assert (

0 commit comments

Comments
 (0)