Skip to content

Conversation

@maxmynter
Copy link
Contributor

Closes #17124

Summary

Add a check whether a native literal contains a newline (e.g. int(+\n1)) in which case we must preserve the parenthesis to not break syntax.

Note: An alternative could have been stripping the newline, but I think if it's there it's there for a reason; if not other formatting rules can take care of it.

Test Plan

Extended the existing snapshot test by the affected case.

@github-actions
Copy link
Contributor

github-actions bot commented Apr 5, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@AlexWaygood AlexWaygood added bug Something isn't working fixes Related to suggested fixes for violations labels Apr 6, 2025
@dscorbett
Copy link

Does arg_code.contains('\n') work when the newline is a carriage return? For example:

$ printf 'int(-\r1)\r' | ruff --isolated check - --select UP018 --diff 2>&1 | grep error:
error: Fix introduced a syntax error. Reverting all changes.

If not, see #15230 and #15703 for ways to detect all newlines.

Comment on lines 164 to 165
int(-
1) # Carriage return as newline
Copy link
Member

Choose a reason for hiding this comment

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

This does not seem to have a carriage return character as newline. It might have been stripped by your either / git. You'd need to create a separate file for this test case and include it in https://github.com/astral-sh/ruff/blob/main/.gitattributes similar to how other files are included there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dang. Mus've been git or pre-commit hooks because i was aware of editor autoformatting and checked it before committing.

@dhruvmanila dhruvmanila changed the title Preserve parenthesis when fixing native literals containing newlines [pyupgrade] Preserve parenthesis when fixing native literals containing newlines (UP018) Apr 10, 2025
@maxmynter
Copy link
Contributor Author

maxmynter commented Apr 11, 2025

I'm unsure how the testfiles will behave when running on different machines and I couldn't test as I have only access to windows machines. So let me know if my approach doesn't work.

For the rules RUF046 and UP018 i've added 2 test fixtures each; one with cr the other with lr newlines. All are persisted in .gitattributes.

Alternatively, we could merge those and use test eol=keep but that runs at the risk of devs running into formatting errors when they edit the fixtures.

@MichaReiser
Copy link
Member

that runs at the risk of devs running into formatting errors when they edit the fixtures.

That's a problem that exists anyway. Not when commiting, but it means they may accidentally change the line ending locally which might be confusing when debugging a test. You can create an .editorconfig file to disable formatting in editors that support and respect .editorconfig

https://github.com/astral-sh/ruff/blob/46ab9dec181f7736a0d32be4bad59d00228c1819/crates/ruff_linter/resources/test/fixtures/pycodestyle/.editorconfig#L9-L8

@maxmynter
Copy link
Contributor Author

I added the .editorconfigs in 67348be.


I think it makes sense to keep the separate files for the cr and lf cases. That way we enforce the desired line endings via .gitattributes, revert any unwanted formatting changes and the tests fail if functionality breaks.

With eol=keep we would keep accidental changes to the file. If these changes slip in, they may easily happen with the snapshot, too.

I've had some issues getting the linebreak's to render in different editors.

What do you think?

@maxmynter maxmynter requested a review from dhruvmanila April 16, 2025 15:40
.gitattributes Outdated
crates/ruff_python_parser/resources/invalid/re_lex_logical_token_mac_eol.py text eol=cr

crates/ruff_linter/resources/test/fixtures/ruff/RUF046_CR.py text eol=cr
crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF046_RUF046_CR.py.snap text eol=cr
Copy link
Member

@dhruvmanila dhruvmanila Apr 21, 2025

Choose a reason for hiding this comment

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

Do we need to include the snapshot files in here? I don't think so considering that other snapshot files aren't included and there are .editorconfig files present in both ruff and pyupgrade snapshot directories.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we need them.

I added both mechanisms for specific reasons:

  • .editorconfig (added in 67348be): Prevents editors from automatically reformatting the test fixtures when opened
  • .gitattributes: Ensures Git maintains specific line endings (CR/LF) during checkout/staging irrespective of OS

This way i want to avoid (1) tests from passing incorrectly (if both files get normalized) or (2) breaking unexpectedly (if only one gets normalized).

In 5edfdc8 I wanted to add tests for CR and LF lineendings but local normalization made tests passing as both were normalized thus not testing for CRs.

The other test cases don't seem to be sensitive to the specific line endings and should be fine as long as both fixture and snapshot are regularized on checkout by git. But fixing only the fixture, not the snapshot could make tests flaky.

Or am I missing something?

Copy link
Member

Choose a reason for hiding this comment

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

Looking at the crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF046_RUF046_CR.py.snap snapshot, it does seem to render the \r differently (^M). That's why I think adding the snapshot here isn't needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Allright, addressed in 005a528.

@maxmynter maxmynter requested a review from dhruvmanila April 23, 2025 22:31
@MichaReiser MichaReiser merged commit a01f251 into astral-sh:main Apr 24, 2025
33 checks passed
dcreager added a commit that referenced this pull request Apr 24, 2025
* main:
  [red-knot] fix collapsing literal and its negation to object (#17605)
  [red-knot] Add more tests for protocols (#17603)
  [red-knot] Ban direct instantiations of `Protocol` classes (#17597)
  [`pyupgrade`] Preserve parenthesis when fixing native literals containing newlines (`UP018`) (#17220)
  [`airflow`] fix typos (`AIR302`, `AIR312`) (#17574)
  [red-knot] Special case `@abstractmethod` for function type (#17591)
  [red-knot] Emit diagnostics for isinstance() and issubclass() calls where a non-runtime-checkable protocol is the second argument (#17561)
  [red-knot] Infer the members of a protocol class (#17556)
  [red-knot] Add `FunctionType::to_overloaded` (#17585)
  [red-knot] Add mdtests for `global` statement (#17563)
  [syntax-errors] Make duplicate parameter names a semantic error (#17131)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working fixes Related to suggested fixes for violations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UP018 fix introduces a syntax error when the argument contains a newline

5 participants