Skip to content

Commit 22619e6

Browse files
authored
Introduce more ruff rules (#230)
1 parent 0edcaa7 commit 22619e6

14 files changed

+127
-127
lines changed

pyproject.toml

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,28 @@ dynamic = [
3131
fix = true
3232
extend-exclude = [
3333
"noxfile.py",
34-
"docs/*"
34+
"docs/*",
3535
]
3636

3737
[tool.ruff.lint]
38-
select = [
39-
"E",
40-
"F",
41-
"W",
42-
"I",
43-
"ISC",
44-
"D",
38+
extend-select = [
39+
"B", # flake8-bugbear
40+
"C4", # flake8-comprehensions
41+
"ERA", # flake8-eradicate/eradicate
42+
"I", # isort
43+
"N", # pep8-naming
44+
"PIE", # flake8-pie
45+
"PGH", # pygrep
46+
"RUF", # ruff checks
47+
"SIM", # flake8-simplify
48+
"T20", # flake8-print
49+
"TCH", # flake8-type-checking
50+
"TID", # flake8-tidy-imports
51+
"UP", # pyupgrade
52+
"D", # pydocstyle
53+
"PTH", # flake8-use-pathlib
54+
"ISC", # implicit-str-concat
55+
"W", # pycodestyle warnings
4556
]
4657
ignore = [
4758
"D105",
@@ -55,11 +66,12 @@ ignore = [
5566
"ISC001",
5667
"ISC002",
5768
"E501",
69+
"N818",
5870
]
5971

6072
[tool.ruff.lint.per-file-ignores]
6173
"tests/*" = ["D"]
62-
"tools/*" = ["D"]
74+
"tools/*" = ["D", "T20"]
6375

6476
[tool.ruff.lint.isort]
6577
known-first-party = ["src"]

src/installer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
__version__ = "1.0.0.dev0"
44
__all__ = ["install"]
55

6-
from installer._core import install # noqa
6+
from installer._core import install

src/installer/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def _get_scheme_dict(
7575
# calculate 'headers' path, not currently in sysconfig - see
7676
# https://bugs.python.org/issue44445. This is based on what distutils does.
7777
# TODO: figure out original vs normalised distribution names
78-
scheme_dict["headers"] = os.path.join(
78+
scheme_dict["headers"] = os.path.join( # noqa: PTH118
7979
sysconfig.get_path("include", vars={"installed_base": installed_base}),
8080
distribution_name,
8181
)

src/installer/_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
__all__ = ["install"]
1414

1515

16-
def _process_WHEEL_file(source: WheelSource) -> Scheme:
16+
def _process_WHEEL_file(source: WheelSource) -> Scheme: # noqa: N802
1717
"""Process the WHEEL file, from ``source``.
1818
1919
Returns the scheme that the archive root should go in.

src/installer/destinations.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,11 @@ class SchemeDictionaryDestination(WheelDestination):
138138
overwrite_existing: bool = False
139139
"""Silently overwrite existing files."""
140140

141-
def _path_with_destdir(self, scheme: Scheme, path: str) -> str:
142-
file = os.path.join(self.scheme_dict[scheme], path)
141+
def _path_with_destdir(self, scheme: Scheme, path: str) -> Path:
142+
file = Path(self.scheme_dict[scheme]) / path
143143
if self.destdir is not None:
144-
file_path = Path(file)
145-
rel_path = file_path.relative_to(file_path.anchor)
146-
return os.path.join(self.destdir, rel_path)
144+
rel_path = file.relative_to(file.anchor)
145+
return Path(self.destdir) / rel_path
147146
return file
148147

149148
def write_to_fs(
@@ -164,15 +163,15 @@ def write_to_fs(
164163
- Hashes the written content, to determine the entry in the ``RECORD`` file.
165164
"""
166165
target_path = self._path_with_destdir(scheme, path)
167-
if not self.overwrite_existing and os.path.exists(target_path):
168-
message = f"File already exists: {target_path}"
166+
if not self.overwrite_existing and target_path.exists():
167+
message = f"File already exists: {target_path!s}"
169168
raise FileExistsError(message)
170169

171-
parent_folder = os.path.dirname(target_path)
172-
if not os.path.exists(parent_folder):
173-
os.makedirs(parent_folder)
170+
parent_folder = target_path.parent
171+
if not parent_folder.exists():
172+
parent_folder.mkdir(parents=True)
174173

175-
with open(target_path, "wb") as f:
174+
with target_path.open("wb") as f:
176175
hash_, size = copyfileobj_with_hashing(stream, f, self.hash_algorithm)
177176

178177
if is_executable:
@@ -234,9 +233,9 @@ def write_script(
234233
)
235234

236235
path = self._path_with_destdir(Scheme("scripts"), script_name)
237-
mode = os.stat(path).st_mode
236+
mode = path.stat().st_mode
238237
mode |= (mode & 0o444) >> 2
239-
os.chmod(path, mode)
238+
path.chmod(mode)
240239

241240
return entry
242241

@@ -248,9 +247,8 @@ def _compile_bytecode(self, scheme: Scheme, record: RecordEntry) -> None:
248247
import compileall
249248

250249
target_path = self._path_with_destdir(scheme, record.path)
251-
dir_path_to_embed = os.path.dirname( # Without destdir
252-
os.path.join(self.scheme_dict[scheme], record.path)
253-
)
250+
dir_path_to_embed = (Path(self.scheme_dict[scheme]) / record.path).parent
251+
254252
for level in self.bytecode_optimization_levels:
255253
compileall.compile_file(
256254
target_path, optimize=level, quiet=1, ddir=dir_path_to_embed

src/installer/records.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import hashlib
66
import os
77
from dataclasses import dataclass
8+
from pathlib import Path
89
from typing import BinaryIO, Iterable, Iterator, Optional, Tuple, cast
910

1011
from installer.utils import copyfileobj_with_hashing, get_stream_length
@@ -152,23 +153,19 @@ def validate_stream(self, stream: BinaryIO) -> bool:
152153
:return: Whether data read from stream matches hash and size.
153154
"""
154155
if self.hash_ is not None:
155-
with open(os.devnull, "wb") as new_target:
156+
with Path(os.devnull).open("wb") as new_target:
156157
hash_, size = copyfileobj_with_hashing(
157158
stream, cast("BinaryIO", new_target), self.hash_.name
158159
)
159160

160161
if self.size is not None and size != self.size:
161162
return False
162-
if self.hash_.value != hash_:
163-
return False
164-
return True
163+
return self.hash_.value == hash_
165164

166165
elif self.size is not None:
167166
assert self.hash_ is None
168167
size = get_stream_length(stream)
169-
if size != self.size:
170-
return False
171-
return True
168+
return size == self.size
172169

173170
return True
174171

src/installer/scripts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def _get_alternate_executable(self, executable: str, kind: "LauncherKind") -> st
8484
if self.section == "gui" and kind != "posix":
8585
dn, fn = os.path.split(executable)
8686
fn = fn.replace("python", "pythonw")
87-
executable = os.path.join(dn, fn)
87+
executable = os.path.join(dn, fn) # noqa: PTH118
8888
return executable
8989

9090
def generate(self, executable: str, kind: "LauncherKind") -> Tuple[str, bytes]:

src/installer/sources.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
"""Source of information about a wheel file."""
22

3-
import os
43
import posixpath
54
import stat
65
import zipfile
76
from contextlib import contextmanager
87
from functools import cached_property
9-
from typing import BinaryIO, ClassVar, Iterator, List, Optional, Tuple, Type, cast
8+
from pathlib import Path
9+
from typing import (
10+
TYPE_CHECKING,
11+
BinaryIO,
12+
ClassVar,
13+
Iterator,
14+
List,
15+
Optional,
16+
Tuple,
17+
Type,
18+
cast,
19+
)
1020

1121
from installer.exceptions import InstallerError
1222
from installer.records import RecordEntry, parse_record_file
1323
from installer.utils import canonicalize_name, parse_wheel_filename
1424

25+
if TYPE_CHECKING:
26+
import os
27+
1528
WheelContentElement = Tuple[Tuple[str, str, str], BinaryIO, bool]
1629

1730

@@ -156,7 +169,7 @@ def __init__(self, f: zipfile.ZipFile) -> None:
156169
self._zipfile = f
157170
assert f.filename
158171

159-
basename = os.path.basename(f.filename)
172+
basename = Path(f.filename).name
160173
parsed_name = parse_wheel_filename(basename)
161174
super().__init__(
162175
version=parsed_name.version,

src/installer/utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from email.message import Message
1414
from email.parser import FeedParser
1515
from email.policy import compat32
16+
from pathlib import Path
1617
from typing import (
1718
TYPE_CHECKING,
1819
BinaryIO,
@@ -22,7 +23,6 @@
2223
NewType,
2324
Optional,
2425
Tuple,
25-
Union,
2626
cast,
2727
)
2828

@@ -67,7 +67,7 @@
6767
"WheelFilename", ["distribution", "version", "build_tag", "tag"]
6868
)
6969

70-
# Adapted from https://github.com/python/importlib_metadata/blob/v3.4.0/importlib_metadata/__init__.py#L90 # noqa
70+
# Adapted from https://github.com/python/importlib_metadata/blob/v3.4.0/importlib_metadata/__init__.py#L90
7171
_ENTRYPOINT_REGEX = re.compile(
7272
r"""
7373
(?P<module>[\w.]+)\s*
@@ -235,7 +235,7 @@ def parse_entrypoints(text: str) -> Iterable[Tuple[str, str, str, "ScriptSection
235235
:return:
236236
name of the script, module to use, attribute to call, kind of script (cli / gui)
237237
"""
238-
# Borrowed from https://github.com/python/importlib_metadata/blob/v3.4.0/importlib_metadata/__init__.py#L115 # noqa
238+
# Borrowed from https://github.com/python/importlib_metadata/blob/v3.4.0/importlib_metadata/__init__.py#L115
239239
config = ConfigParser(delimiters="=")
240240
config.optionxform = str # type: ignore[assignment, method-assign]
241241
config.read_string(text)
@@ -271,6 +271,6 @@ def _current_umask() -> int:
271271

272272
# Borrowed from:
273273
# https://github.com/pypa/pip/blob/0f21fb92/src/pip/_internal/utils/unpacking.py#L93
274-
def make_file_executable(path: Union[str, "os.PathLike[str]"]) -> None:
274+
def make_file_executable(path: Path) -> None:
275275
"""Make the file at the provided path executable."""
276-
os.chmod(path, (0o777 & ~_current_umask() | 0o111))
276+
path.chmod(0o777 & ~_current_umask() | 0o111)

tests/test_destinations.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import io
2-
import os.path
2+
from pathlib import Path
33

44
import pytest
55

@@ -86,10 +86,7 @@ def destination_overwrite_existing(self, tmp_path):
8686
)
8787
def test_write_file(self, destination, scheme, path, data, expected):
8888
record = destination.write_file(scheme, path, io.BytesIO(data), False)
89-
file_path = os.path.join(destination.scheme_dict[scheme], path)
90-
with open(file_path, "rb") as f:
91-
file_data = f.read()
92-
89+
file_data = (Path(destination.scheme_dict[scheme]) / path).read_bytes()
9390
assert file_data == expected
9491
assert record.path == path
9592

@@ -111,12 +108,11 @@ def test_write_record_duplicate_with_overwrite_existing(
111108
def test_write_script(self, destination):
112109
script_args = ("my_entrypoint", "my_module", "my_function", "console")
113110
record = destination.write_script(*script_args)
114-
file_path = os.path.join(destination.scheme_dict["scripts"], "my_entrypoint")
111+
file_path = Path(destination.scheme_dict["scripts"]) / "my_entrypoint"
115112

116-
assert os.path.isfile(file_path)
113+
assert file_path.is_file()
117114

118-
with open(file_path, "rb") as f:
119-
file_data = f.read()
115+
file_data = file_path.read_bytes()
120116
name, expected_data = Script(*script_args).generate("/my/python", "posix")
121117

122118
assert file_data == expected_data
@@ -179,11 +175,9 @@ def test_finalize_write_record(self, destination):
179175
]
180176

181177
destination.finalize_installation("purelib", "RECORD", records)
182-
file_path = os.path.join(destination.scheme_dict["purelib"], "RECORD")
183-
184-
with open(file_path, "rb") as f:
185-
data = f.read()
178+
file_path = Path(destination.scheme_dict["purelib"]) / "RECORD"
186179

180+
data = file_path.read_bytes()
187181
assert data == (
188182
b"RECORD,,\n"
189183
b"../data/my_data1.bin,sha256=NV0A-M4OPuqTsHjeD6Wth_-UqrpAAAdyplcustFZ8s4,9\n"

tests/test_records.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from io import BytesIO
2+
from pathlib import Path
23

34
import pytest
45

@@ -25,7 +26,7 @@ def record_simple_iter(record_simple_list):
2526
def record_simple_file(tmpdir, record_simple_list):
2627
p = tmpdir.join("RECORD")
2728
p.write("\n".join(record_simple_list))
28-
with open(str(p)) as f:
29+
with Path(p).open() as f:
2930
yield f
3031

3132

tests/test_scripts.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import io
2-
import os
32
import zipfile
3+
from pathlib import Path
44

55
import pytest
66

@@ -32,12 +32,8 @@ def test_script_generate_space_in_executable():
3232
def _read_launcher_data(section, kind):
3333
prefix = {"console": "t", "gui": "w"}[section]
3434
suffix = {"win-ia32": "32", "win-amd64": "64", "win-arm": "_arm"}[kind]
35-
filename = os.path.join(
36-
os.path.dirname(os.path.abspath(_scripts.__file__)),
37-
f"{prefix}{suffix}.exe",
38-
)
39-
with open(filename, "rb") as f:
40-
return f.read()
35+
file = Path(_scripts.__file__).parent / f"{prefix}{suffix}.exe"
36+
return file.read_bytes()
4137

4238

4339
@pytest.mark.parametrize("section", ["console", "gui"])

0 commit comments

Comments
 (0)