Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pyupgrade] Automatically rewrite format-strings to f-strings #1905

Merged
merged 28 commits into from
Jan 17, 2023
Merged

[pyupgrade] Automatically rewrite format-strings to f-strings #1905

merged 28 commits into from
Jan 17, 2023

Conversation

colin99d
Copy link
Contributor

Draft opened for visibility. This is a part of #827. This PR is currently affected by the \N{emoji} bug that we are searching for a fix for.

@colin99d colin99d changed the title Fstrings Pyupgrade: Fstrings Jan 16, 2023
@colin99d
Copy link
Contributor Author

colin99d commented Jan 16, 2023

@charliermarsh this pr is ready except for the questions below, so I will move it out of draft. Before this is merged we need to consider or resolve the following items:

  1. The /N{emoji} issue from UP031 remains unsolved (whenever we solve it I will integrate the solution here.
  2. F strings introduce double bracket syntax {{}}, which is throwing my regexs for a loop. Currently, the best solution I have is \{(?P<name>[^\W0-9]\w*)?(?P<fmt>[^{]*?)} (this does NOT work fully). I tried using libcst_native but it just gives a normal string, and not a formatted one. I believe we could use fancy_regex here; however, that adds a whole dependency for one small functionality. As always, we could just only check for this and not fix it.
  3. Similar to my PR for UP031, there is a negative test case I disagree with.
"{}" . format(x)

This is not supposed to be formatted because of its "weird syntax", but our AST parser ignores the spaces. This means ignoring this is more work for us, and results in a worse user experience.
4. Lastly (and this one is kinda embarrassing). I cannot for the life of me get the proper .snap file to generate for tests. I have never had an issue before, but it keeps suggesting that the snap just be an empty list, even though running ruff on those files produces a lot of changes. I am sure its something small I am missing.

@colin99d colin99d marked this pull request as ready for review January 16, 2023 20:33
}

/// Returns true if the statement and function call match, and false if not
fn check_with_summary(&self, summary: &FormatSummary) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

@colin99d - Is this strictly necessary? (Do you know of any case where it would trigger?)

@charliermarsh
Copy link
Member

@colin99d - I'm fine to ignore the unicode case. What else needs solving here? The {{}} case?

@colin99d
Copy link
Contributor Author

That should be the only thing!

@charliermarsh
Copy link
Member

charliermarsh commented Jan 17, 2023

I have one idea I'd like to try, which may let us avoid regexes.

@charliermarsh
Copy link
Member

(As-is, what happens in those cases? We just ignore them?)

@colin99d
Copy link
Contributor Author

colin99d commented Jan 17, 2023

(As-is, what happens in those cases? We just ignore them?)

Right now it is ignored in a way. For example: below rust thinks it needs three arguments but only finds 2, so it exits. If we are going to ignore these, we should probably implement some better logic for ignoring them.
{}{{}}{}".format(escaped, y)

@charliermarsh
Copy link
Member

I think we can leverage RustPython's actual string parser and forego regular expressions. Trying it now...

@charliermarsh charliermarsh changed the title Pyupgrade: Fstrings Pyupgrade: automatically rewrite format-strings to f-strings Jan 17, 2023
@charliermarsh charliermarsh changed the title Pyupgrade: automatically rewrite format-strings to f-strings [pyupgrade] Automatically rewrite format-strings to f-strings Jan 17, 2023
@charliermarsh
Copy link
Member

@colin99d - I was able to use RustPython's own parser, and I think it's properly handling all test-cases now.

This might be a useful approach to use in the other PR too? I haven't looked into it deeply, but generally, it's best to use the RustPython parsers where we can.

@charliermarsh charliermarsh merged commit 1730f2a into astral-sh:main Jan 17, 2023
renovate bot added a commit to ixm-one/pytest-cmake-presets that referenced this pull request Jan 17, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [ruff](https://togithub.com/charliermarsh/ruff) | `^0.0.223` ->
`^0.0.224` |
[![age](https://badges.renovateapi.com/packages/pypi/ruff/0.0.224/age-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://badges.renovateapi.com/packages/pypi/ruff/0.0.224/adoption-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://badges.renovateapi.com/packages/pypi/ruff/0.0.224/compatibility-slim/0.0.223)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://badges.renovateapi.com/packages/pypi/ruff/0.0.224/confidence-slim/0.0.223)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>charliermarsh/ruff</summary>

###
[`v0.0.224`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.224)

[Compare
Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.223...v0.0.224)

#### What's Changed

- Re-run benchmark and update documentation by
[@&#8203;charliermarsh](https://togithub.com/charliermarsh) in
[astral-sh/ruff#1907
- Derive Hash instead of implementing it by hand by
[@&#8203;not-my-profile](https://togithub.com/not-my-profile) in
[astral-sh/ruff#1890
- Add backticks to B904's message by
[@&#8203;harupy](https://togithub.com/harupy) in
[astral-sh/ruff#1914
- Refactor `flake8_tidy_imports` by
[@&#8203;not-my-profile](https://togithub.com/not-my-profile) in
[astral-sh/ruff#1909
- Trigger update to pre-commit mirror after pypi publish by
[@&#8203;pmbarrett314](https://togithub.com/pmbarrett314) in
[astral-sh/ruff#1910
- Rewrite `lru_cache` to `cache` on Python 3.9+ by
[@&#8203;charliermarsh](https://togithub.com/charliermarsh) in
[astral-sh/ruff#1918
- Avoid syntax errors when fixing parenthesized unused variables by
[@&#8203;charliermarsh](https://togithub.com/charliermarsh) in
[astral-sh/ruff#1919
- Add some new testimonials by
[@&#8203;charliermarsh](https://togithub.com/charliermarsh) in
[astral-sh/ruff#1921
- Avoid removing statements that contain side-effects by
[@&#8203;charliermarsh](https://togithub.com/charliermarsh) in
[astral-sh/ruff#1920
- Add benchmark scripts for no-IO by
[@&#8203;charliermarsh](https://togithub.com/charliermarsh) in
[astral-sh/ruff#1925
- Add flake8-pie PIE796: prefer-unique-enum by
[@&#8203;ljesparis](https://togithub.com/ljesparis) in
[astral-sh/ruff#1923
- \[pyupgrade] Automatically rewrite format-strings to f-strings by
[@&#8203;colin99d](https://togithub.com/colin99d) in
[astral-sh/ruff#1905

#### New Contributors

- [@&#8203;pmbarrett314](https://togithub.com/pmbarrett314) made their
first contribution in
[astral-sh/ruff#1910
- [@&#8203;ljesparis](https://togithub.com/ljesparis) made their first
contribution in
[astral-sh/ruff#1923

**Full Changelog**:
astral-sh/ruff@v0.0.223...v0.0.224

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://app.renovatebot.com/dashboard#github/ixm-one/pytest-cmake-presets).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xMDIuNyIsInVwZGF0ZWRJblZlciI6IjM0LjEwMi43In0=-->

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@nstarman nstarman mentioned this pull request Jan 18, 2023
10 tasks
MichaReiser added a commit that referenced this pull request Mar 6, 2024
…regardless of line-length (`UP032`) (#10238)

## Summary

Fixes #10235

This PR changes `UP032` to flag all `"".format` calls that can
technically be rewritten to an f-string, even if rewritting it to an
fstring, at least automatically, exceeds the line length (or increases
the amount by which it goes over the line length).

I looked at the Git history to understand whether the check prevents
some false positives (reported by an issue), but i haven't found a
compelling reason to limit the rule to only flag format calls that stay
in the line length limit:

* #7818 Changed the heuristic to
determine if the fix fits to address
#7810
* #1905 first version of the rule 


I did take a look at pyupgrade and couldn't find a similar check, at
least not in the rule code (maybe it's checked somewhere else?)
https://github.com/asottile/pyupgrade/blob/main/pyupgrade/_plugins/fstrings.py


## Breaking Change?

This could be seen as a breaking change according to ruff's [versioning
policy](https://docs.astral.sh/ruff/versioning/):

> The behavior of a stable rule is changed
  
  * The scope of a stable rule is significantly increased
  * The intent of the rule changes
* Does not include bug fixes that follow the original intent of the rule

It does increase the scope of the rule, but it is in the original intent
of the rule (so it's not).

## Test Plan

See changed test output
nkxxll pushed a commit to nkxxll/ruff that referenced this pull request Mar 10, 2024
…regardless of line-length (`UP032`) (astral-sh#10238)

## Summary

Fixes astral-sh#10235

This PR changes `UP032` to flag all `"".format` calls that can
technically be rewritten to an f-string, even if rewritting it to an
fstring, at least automatically, exceeds the line length (or increases
the amount by which it goes over the line length).

I looked at the Git history to understand whether the check prevents
some false positives (reported by an issue), but i haven't found a
compelling reason to limit the rule to only flag format calls that stay
in the line length limit:

* astral-sh#7818 Changed the heuristic to
determine if the fix fits to address
astral-sh#7810
* astral-sh#1905 first version of the rule 


I did take a look at pyupgrade and couldn't find a similar check, at
least not in the rule code (maybe it's checked somewhere else?)
https://github.com/asottile/pyupgrade/blob/main/pyupgrade/_plugins/fstrings.py


## Breaking Change?

This could be seen as a breaking change according to ruff's [versioning
policy](https://docs.astral.sh/ruff/versioning/):

> The behavior of a stable rule is changed
  
  * The scope of a stable rule is significantly increased
  * The intent of the rule changes
* Does not include bug fixes that follow the original intent of the rule

It does increase the scope of the rule, but it is in the original intent
of the rule (so it's not).

## Test Plan

See changed test output
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.

None yet

2 participants