Skip to content

Commit 2faf709

Browse files
authored
STY: Enable ruff perflint (#54236)
* some check implmented * Include rules * Enable perflint * type
1 parent b3b1beb commit 2faf709

20 files changed

+102
-111
lines changed

doc/source/conf.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,8 @@
348348
methods = [
349349
x for x in dir(klass) if not x.startswith("_") or x in ("__iter__", "__array__")
350350
]
351-
352-
for method in methods:
353-
# ... and each of its public methods
354-
moved_api_pages.append((f"{old}.{method}", f"{new}.{method}"))
351+
# ... and each of its public methods
352+
moved_api_pages.extend((f"{old}.{method}", f"{new}.{method}") for method in methods)
355353

356354
if include_api:
357355
html_additional_pages = {

pandas/core/frame.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -5815,21 +5815,21 @@ def set_index(
58155815
# GH 49473 Use "lazy copy" with Copy-on-Write
58165816
frame = self.copy(deep=None)
58175817

5818-
arrays = []
5818+
arrays: list[Index] = []
58195819
names: list[Hashable] = []
58205820
if append:
58215821
names = list(self.index.names)
58225822
if isinstance(self.index, MultiIndex):
5823-
for i in range(self.index.nlevels):
5824-
arrays.append(self.index._get_level_values(i))
5823+
arrays.extend(
5824+
self.index._get_level_values(i) for i in range(self.index.nlevels)
5825+
)
58255826
else:
58265827
arrays.append(self.index)
58275828

58285829
to_remove: list[Hashable] = []
58295830
for col in keys:
58305831
if isinstance(col, MultiIndex):
5831-
for n in range(col.nlevels):
5832-
arrays.append(col._get_level_values(n))
5832+
arrays.extend(col._get_level_values(n) for n in range(col.nlevels))
58335833
names.extend(col.names)
58345834
elif isinstance(col, (Index, Series)):
58355835
# if Index then not MultiIndex (treated above)

pandas/core/groupby/generic.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,7 @@ def _aggregate_multiple_funcs(self, arg, *args, **kwargs) -> DataFrame:
345345
arg = [(x, x) if not isinstance(x, (tuple, list)) else x for x in arg]
346346
else:
347347
# list of functions / function names
348-
columns = []
349-
for f in arg:
350-
columns.append(com.get_callable_name(f) or f)
351-
348+
columns = (com.get_callable_name(f) or f for f in arg)
352349
arg = zip(columns, arg)
353350

354351
results: dict[base.OutputKey, DataFrame | Series] = {}

pandas/core/internals/managers.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,7 @@ def get_bool_data(self, copy: bool = False) -> Self:
458458

459459
elif blk.is_object:
460460
nbs = blk._split()
461-
for nb in nbs:
462-
if nb.is_bool:
463-
new_blocks.append(nb)
461+
new_blocks.extend(nb for nb in nbs if nb.is_bool)
464462

465463
return self._combine(new_blocks, copy)
466464

pandas/core/methods/describe.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,12 @@ def _select_data(self) -> DataFrame:
202202
def reorder_columns(ldesc: Sequence[Series]) -> list[Hashable]:
203203
"""Set a convenient order for rows for display."""
204204
names: list[Hashable] = []
205+
seen_names: set[Hashable] = set()
205206
ldesc_indexes = sorted((x.index for x in ldesc), key=len)
206207
for idxnames in ldesc_indexes:
207208
for name in idxnames:
208-
if name not in names:
209+
if name not in seen_names:
210+
seen_names.add(name)
209211
names.append(name)
210212
return names
211213

pandas/core/reshape/reshape.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,7 @@ def _unstack_multiple(
467467
new_names = [data.columns.name] + cnames
468468

469469
new_codes = [unstcols.codes[0]]
470-
for rec in recons_codes:
471-
new_codes.append(rec.take(unstcols.codes[-1]))
470+
new_codes.extend(rec.take(unstcols.codes[-1]) for rec in recons_codes)
472471

473472
new_columns = MultiIndex(
474473
levels=new_levels, codes=new_codes, names=new_names, verify_integrity=False

pandas/io/excel/_odfreader.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ def get_sheet_data(
154154
# add blank rows to our table
155155
table.extend([[self.empty_value]] * empty_rows)
156156
empty_rows = 0
157-
for _ in range(row_repeat):
158-
table.append(table_row)
157+
table.extend(table_row for _ in range(row_repeat))
159158
if file_rows_needed is not None and len(table) >= file_rows_needed:
160159
break
161160

pandas/io/formats/printing.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ def adjoin(space: int, *lists: list[str], **kwargs) -> str:
4444
strlen = kwargs.pop("strlen", len)
4545
justfunc = kwargs.pop("justfunc", justify)
4646

47-
out_lines = []
4847
newLists = []
4948
lengths = [max(map(strlen, x)) + space for x in lists[:-1]]
5049
# not the last one
@@ -55,9 +54,7 @@ def adjoin(space: int, *lists: list[str], **kwargs) -> str:
5554
nl = ([" " * lengths[i]] * (maxLen - len(lst))) + nl
5655
newLists.append(nl)
5756
toJoin = zip(*newLists)
58-
for lines in toJoin:
59-
out_lines.append("".join(lines))
60-
return "\n".join(out_lines)
57+
return "\n".join("".join(lines) for lines in toJoin)
6158

6259

6360
def justify(texts: Iterable[str], max_len: int, mode: str = "right") -> list[str]:

pandas/io/parsers/python_parser.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -865,15 +865,16 @@ def _remove_empty_lines(self, lines: list[list[Scalar]]) -> list[list[Scalar]]:
865865
filtered_lines : list of list of Scalars
866866
The same array of lines with the "empty" ones removed.
867867
"""
868-
ret = []
869-
for line in lines:
870-
# Remove empty lines and lines with only one whitespace value
868+
# Remove empty lines and lines with only one whitespace value
869+
ret = [
870+
line
871+
for line in lines
871872
if (
872873
len(line) > 1
873874
or len(line) == 1
874875
and (not isinstance(line[0], str) or line[0].strip())
875-
):
876-
ret.append(line)
876+
)
877+
]
877878
return ret
878879

879880
def _check_thousands(self, lines: list[list[Scalar]]) -> list[list[Scalar]]:

pandas/tests/groupby/aggregate/test_aggregate.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1313,8 +1313,7 @@ def test_groupby_combined_aggs_cat_cols(grp_col_dict, exp_data):
13131313
multi_index_list = []
13141314
for k, v in grp_col_dict.items():
13151315
if isinstance(v, list):
1316-
for value in v:
1317-
multi_index_list.append([k, value])
1316+
multi_index_list.extend([k, value] for value in v)
13181317
else:
13191318
multi_index_list.append([k, v])
13201319
multi_index = MultiIndex.from_tuples(tuple(multi_index_list))

pandas/tests/groupby/test_indexing.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,12 @@ def test_against_head_and_tail(arg, method, simulated):
188188
result = grouped._positional_selector[:arg]
189189

190190
if simulated:
191-
indices = []
192-
for j in range(size):
193-
for i in range(n_groups):
194-
if j * n_groups + i < n_groups * n_rows_per_group:
195-
indices.append(j * n_groups + i)
196-
191+
indices = [
192+
j * n_groups + i
193+
for j in range(size)
194+
for i in range(n_groups)
195+
if j * n_groups + i < n_groups * n_rows_per_group
196+
]
197197
expected = df.iloc[indices]
198198

199199
else:
@@ -203,12 +203,12 @@ def test_against_head_and_tail(arg, method, simulated):
203203
result = grouped._positional_selector[-arg:]
204204

205205
if simulated:
206-
indices = []
207-
for j in range(size):
208-
for i in range(n_groups):
209-
if (n_rows_per_group + j - size) * n_groups + i >= 0:
210-
indices.append((n_rows_per_group + j - size) * n_groups + i)
211-
206+
indices = [
207+
(n_rows_per_group + j - size) * n_groups + i
208+
for j in range(size)
209+
for i in range(n_groups)
210+
if (n_rows_per_group + j - size) * n_groups + i >= 0
211+
]
212212
expected = df.iloc[indices]
213213

214214
else:

pandas/tests/io/json/test_pandas.py

+17-23
Original file line numberDiff line numberDiff line change
@@ -1366,9 +1366,9 @@ def test_to_jsonl(self):
13661366

13671367
# TODO: there is a near-identical test for pytables; can we share?
13681368
@pytest.mark.xfail(reason="GH#13774 encoding kwarg not supported", raises=TypeError)
1369-
def test_latin_encoding(self):
1370-
# GH 13774
1371-
values = [
1369+
@pytest.mark.parametrize(
1370+
"val",
1371+
[
13721372
[b"E\xc9, 17", b"", b"a", b"b", b"c"],
13731373
[b"E\xc9, 17", b"a", b"b", b"c"],
13741374
[b"EE, 17", b"", b"a", b"b", b"c"],
@@ -1378,26 +1378,20 @@ def test_latin_encoding(self):
13781378
[b"A\xf8\xfc", b"", b"a", b"b", b"c"],
13791379
[np.nan, b"", b"b", b"c"],
13801380
[b"A\xf8\xfc", np.nan, b"", b"b", b"c"],
1381-
]
1382-
1383-
values = [
1384-
[x.decode("latin-1") if isinstance(x, bytes) else x for x in y]
1385-
for y in values
1386-
]
1387-
1388-
examples = []
1389-
for dtype in ["category", object]:
1390-
for val in values:
1391-
examples.append(Series(val, dtype=dtype))
1392-
1393-
def roundtrip(s, encoding="latin-1"):
1394-
with tm.ensure_clean("test.json") as path:
1395-
s.to_json(path, encoding=encoding)
1396-
retr = read_json(StringIO(path), encoding=encoding)
1397-
tm.assert_series_equal(s, retr, check_categorical=False)
1398-
1399-
for s in examples:
1400-
roundtrip(s)
1381+
],
1382+
)
1383+
@pytest.mark.parametrize("dtype", ["category", object])
1384+
def test_latin_encoding(self, dtype, val):
1385+
# GH 13774
1386+
ser = Series(
1387+
[x.decode("latin-1") if isinstance(x, bytes) else x for x in val],
1388+
dtype=dtype,
1389+
)
1390+
encoding = "latin-1"
1391+
with tm.ensure_clean("test.json") as path:
1392+
ser.to_json(path, encoding=encoding)
1393+
retr = read_json(StringIO(path), encoding=encoding)
1394+
tm.assert_series_equal(ser, retr, check_categorical=False)
14011395

14021396
def test_data_frame_size_after_to_json(self):
14031397
# GH15344

pandas/tests/series/accessors/test_cat_accessor.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,9 @@ def test_dt_accessor_api_for_categorical(self, idx):
193193
]
194194

195195
func_defs = [(fname, (), {}) for fname in func_names]
196-
197-
for f_def in special_func_defs:
198-
if f_def[0] in dir(ser.dt):
199-
func_defs.append(f_def)
196+
func_defs.extend(
197+
f_def for f_def in special_func_defs if f_def[0] in dir(ser.dt)
198+
)
200199

201200
for func, args, kwargs in func_defs:
202201
with warnings.catch_warnings():

pandas/tests/test_sorting.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,14 @@ def test_int64_overflow_one_to_many_none_match(self, how, sort):
297297

298298
for k, rval in rdict.items():
299299
if k not in ldict:
300-
for rv in rval:
301-
vals.append(
302-
k
303-
+ (
304-
np.nan,
305-
rv,
306-
)
300+
vals.extend(
301+
k
302+
+ (
303+
np.nan,
304+
rv,
307305
)
306+
for rv in rval
307+
)
308308

309309
def align(df):
310310
df = df.sort_values(df.columns.tolist())

pyproject.toml

+11-3
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,15 @@ select = [
240240
# Ruff-specific rules
241241
"RUF",
242242
# flake8-bandit: exec-builtin
243-
"S102"
243+
"S102",
244+
# Perflint
245+
"PERF",
244246
]
245247

246248
ignore = [
249+
### Intentionally disabled
247250
# space before : (needed for how black formats slicing)
248-
# "E203", # not yet implemented
251+
"E203",
249252
# module level import not at top of file
250253
"E402",
251254
# do not assign a lambda expression, use a def
@@ -302,8 +305,13 @@ ignore = [
302305
# "PYI027", # not yet implemented
303306
# while int | float can be shortened to float, the former is more explicit
304307
# "PYI041", # not yet implemented
308+
# incorrect-dict-iterator, flags valid Series.items usage
309+
"PERF102",
310+
# try-except-in-loop, becomes useless in Python 3.11
311+
"PERF203",
305312

306-
# Additional checks that don't pass yet
313+
314+
### TODO: Enable gradually
307315
# Useless statement
308316
"B018",
309317
# Within an except clause, raise exceptions with ...

scripts/no_bool_in_generic.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ def visit(tree: ast.Module) -> dict[int, list[int]]:
4242
if isinstance(value, ast.AST):
4343
nodes.append((next_in_annotation, value))
4444
elif isinstance(value, list):
45-
for value in reversed(value):
46-
if isinstance(value, ast.AST):
47-
nodes.append((next_in_annotation, value))
45+
nodes.extend(
46+
(next_in_annotation, value)
47+
for value in reversed(value)
48+
if isinstance(value, ast.AST)
49+
)
4850

4951
return to_replace
5052

scripts/validate_docstrings.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -271,15 +271,15 @@ def pandas_validate(func_name: str):
271271
)
272272

273273
if doc.see_also:
274-
for rel_name in doc.see_also:
275-
if rel_name.startswith("pandas."):
276-
result["errors"].append(
277-
pandas_error(
278-
"SA05",
279-
reference_name=rel_name,
280-
right_reference=rel_name[len("pandas.") :],
281-
)
282-
)
274+
result["errors"].extend(
275+
pandas_error(
276+
"SA05",
277+
reference_name=rel_name,
278+
right_reference=rel_name[len("pandas.") :],
279+
)
280+
for rel_name in doc.see_also
281+
if rel_name.startswith("pandas.")
282+
)
283283

284284
result["examples_errs"] = ""
285285
if doc.examples:
@@ -300,11 +300,11 @@ def pandas_validate(func_name: str):
300300
)
301301
)
302302
examples_source_code = "".join(doc.examples_source_code)
303-
for wrong_import in ("numpy", "pandas"):
304-
if f"import {wrong_import}" in examples_source_code:
305-
result["errors"].append(
306-
pandas_error("EX04", imported_library=wrong_import)
307-
)
303+
result["errors"].extend(
304+
pandas_error("EX04", imported_library=wrong_import)
305+
for wrong_import in ("numpy", "pandas")
306+
if f"import {wrong_import}" in examples_source_code
307+
)
308308

309309
if doc.non_hyphenated_array_like():
310310
result["errors"].append(pandas_error("GL05"))

scripts/validate_unwanted_patterns.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,11 @@ def nodefault_used_not_only_for_typing(file_obj: IO[str]) -> Iterable[tuple[int,
392392
if isinstance(value, ast.AST):
393393
nodes.append((next_in_annotation, value))
394394
elif isinstance(value, list):
395-
for value in reversed(value):
396-
if isinstance(value, ast.AST):
397-
nodes.append((next_in_annotation, value))
395+
nodes.extend(
396+
(next_in_annotation, value)
397+
for value in reversed(value)
398+
if isinstance(value, ast.AST)
399+
)
398400

399401

400402
def main(

0 commit comments

Comments
 (0)