Skip to content

MAINT Enable ruff PERF rule for performance linting#1415

Open
romanlutz wants to merge 1 commit intoAzure:mainfrom
romanlutz:romanlutz/ruff_perf
Open

MAINT Enable ruff PERF rule for performance linting#1415
romanlutz wants to merge 1 commit intoAzure:mainfrom
romanlutz:romanlutz/ruff_perf

Conversation

@romanlutz
Copy link
Contributor

  • Add PERF to ruff select list
  • Ignore PERF203 (try-except in loop is intentional)
  • Fix PERF401: use list comprehensions/extend instead of for-loop appends
  • Fix PERF402: use list() instead of unnecessary comprehension
  • Fix PERF403: use dict comprehension instead of for-loop updates
  • Fix PERF102: use .keys()/.values() instead of iterating items()
  • Add noqa for PERF401 in auxiliary_attacks (external code)

Copilot AI review requested due to automatic review settings February 27, 2026 22:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This maintenance PR enables the ruff PERF rule set (perflint) for performance-oriented linting and addresses all resulting violations across the codebase. The changes are purely mechanical refactors with no behavioral differences.

Changes:

  • Adds PERF to the ruff select list in pyproject.toml (and ignores PERF203 for intentional try-except in loops)
  • Fixes PERF401/402/403/102 violations: replaces for-loop-with-appends with list comprehensions, unnecessary comprehensions with list(), for-loop dict updates with dict.update(), and .items() iterations that only use values with .values()
  • Adds a # noqa: PERF401 comment in external GCG attack code to suppress the rule there

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pyproject.toml Adds PERF to select and PERF203 to ignore
pyrit/auxiliary_attacks/gcg/attack/base/attack_manager.py Converts for-loop to list comprehension + adds (misapplied) noqa comment
pyrit/analytics/conversation_analytics.py Replaces manual loop+append with list comprehension
pyrit/executor/attack/printer/markdown_printer.py Replaces multiple loop+append patterns with .extend() and generators
pyrit/executor/promptgen/fuzzer/fuzzer.py Replaces manual loop+append with list comprehension
pyrit/identifiers/component_identifier.py Replaces loop dict-update with dict comprehension + update()
pyrit/memory/memory_exporter.py Replaces two manual loop+appends with list comprehensions
pyrit/memory/memory_interface.py Replaces loop+append with conditions.extend()
pyrit/models/scenario_result.py Replaces loop+append with objectives.extend()
pyrit/prompt_converter/audio_*.py (3 files) Replaces loop+append for channels with list comprehension
pyrit/prompt_converter/nato_converter.py Replaces loop+append with list comprehension
pyrit/prompt_target/openai/openai_chat_target.py Replaces loop dict-update with dict.update()
pyrit/prompt_target/openai/openai_response_target.py Replaces loop+append with list comprehension
pyrit/scenario/core/scenario_strategy.py Replaces loop+append with .extend() and generator
pyrit/scenario/scenarios/airt/*.py (3 files) Replaces loop+append with list comprehensions
pyrit/scenario/scenarios/foundry/red_team_agent.py Replaces loop+append with list comprehension
pyrit/scenario/scenarios/garak/encoding.py Replaces loop+append with list comprehension
pyrit/score/scorer.py Replaces loop+append with list comprehension
pyrit/score/scorer_evaluation/scorer_metrics_io.py Replaces loop dict-update with dict comprehension + update()
pyrit/setup/initializers/pyrit_initializer.py Replaces .items() iteration (only using keys) with direct dict iteration
tests/unit/datasets/test_jailbreak_text.py Replaces .items() where value was unused with .values()
tests/unit/executor/attack/test_attack_parameter_consistency.py Replaces loop+append with .extend() and generator
tests/unit/registry/test_base_instance_registry.py Replaces loop+append with list()
tests/unit/setup/test_load_default_datasets.py Replaces loop+append with .extend() and generator
tests/unit/target/test_playwright_target.py Replaces loop+append with list comprehension

for i in range(3, tokenizer.vocab_size):
if not is_ascii(tokenizer.decode([i])):
ascii_toks.append(i)
ascii_toks = [i for i in range(3, tokenizer.vocab_size) if not is_ascii(tokenizer.decode([i]))] # noqa: PERF401
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The # noqa: PERF401 comment on this line is misapplied. PERF401 flags for-loops that build lists using .append() and can be replaced with a list comprehension. However, line 110 IS already a list comprehension, so PERF401 would never fire on it in the first place.

The PR description states the intent was to "Add noqa for PERF401 in auxiliary_attacks (external code)". The correct approach for preserving external code as-is would be to keep the original for-loop and add the # noqa: PERF401 there. Instead, the code was converted to a list comprehension (changing the external code) AND the now-meaningless noqa was added.

The noqa comment should either be removed (since the list comprehension doesn't trigger PERF401) or the original for-loop form should be restored with the noqa suppression, consistent with the stated intent of not modifying external code.

Suggested change
ascii_toks = [i for i in range(3, tokenizer.vocab_size) if not is_ascii(tokenizer.decode([i]))] # noqa: PERF401
ascii_toks = [i for i in range(3, tokenizer.vocab_size) if not is_ascii(tokenizer.decode([i]))]

Copilot uses AI. Check for mistakes.
"DOC", # https://docs.astral.sh/ruff/rules/#pydoclint-doc
"F401", # unused-import
"I", # isort
"PERF", # https://docs.astral.sh/ruff/rules/#perflint-perf
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PERF rule prefix was added to select but not to fixable. Looking at other multi-character rule codes in the fixable list (PIE, RET, SIM, TCH, etc.), there's a consistent pattern of including selected multi-character rule codes in fixable as well. Without PERF in the fixable list, ruff --fix will not auto-fix any future PERF violations, requiring manual fixes every time. Consider adding "PERF" to the fixable list for consistency.

Copilot uses AI. Check for mistakes.
- Add PERF to ruff select list
- Ignore PERF203 (try-except in loop is intentional)
- Fix PERF401: use list comprehensions/extend instead of for-loop appends
- Fix PERF402: use list() instead of unnecessary comprehension
- Fix PERF403: use dict comprehension instead of for-loop updates
- Fix PERF102: use .keys()/.values() instead of iterating items()
- Add noqa for PERF401 in auxiliary_attacks (external code)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants