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: Format specifiers #1594
Conversation
I will try to have this done by Sunday night. |
@charliermarsh I have the following function to detect expressions:
It works fine for an expression like this:
But the second you make it multi-line like so:
The whole thing fails. Is this an error with my coding, or an error with libcst_native? |
I'm wondering if you need to dedent the code. You might be passing |
It looks like the issue still happens with the de-indented code: 'foo{0}'\n'bar{1}'.format(1, 2). |
…UP_DELETEME.py --no-cache --select UP
thread 'main' panicked at 'called Looks like this is a parse error from the
Just let me know which you would like for me to pursue. |
Would you be open to filing an issue on the LibCST repo? In the meantime, we could just skip those cases. (Are they needed for detection, or just autofixing?) |
Here is the issue: |
new_call, | ||
expr.location, | ||
expr.end_location.unwrap(), | ||
)); | ||
} | ||
checker.add_check(check); | ||
checker.diagnostics.push(diagnostic); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you and sorry that this all churned mid-PR for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im never going to complain about you making this project easier to contribute to.
Hey @charliermarsh I got all the positive test cases working (except for the one edge case we talked about), and all the negative cases working except one. I wanted to get your feedback before I implemented it.
Since the format specifier is split into two different strings, it is NOT supposed to be formatted. However, both the Expr |
I think it's best just to ignore it (i.e., treat it as if there is no space). It strikes me as exceptionally rare, to the point that it's likely either a mistake or that it's not worth adding more complexity to our own implementation to handle it. |
We could probably detect it by tokenizing... but it doesn't seem worth it to me. |
100% agree, especially since the python code will still work. |
I just need to fix one bug with this edge case, and then I should be able to take this PR out of draft. |
@charliermarsh anything else you want to see from this for merge? |
@colin99d - Will review this tonight! |
// FOR REVIEWER: If the new and old are identical, don't create a fix. Pyupgrade | ||
// doesnt even want me to report this, so we could just have an enum for errors, | ||
// and if a special one is returned here then we dont even report a fix | ||
if module_text == final_state.to_string() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When does this happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah nevermind.
} | ||
|
||
/// UP030 | ||
pub(crate) fn format_literals(checker: &mut Checker, summary: &FormatSummary, expr: &Expr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@colin99d - It turns out that we already had a utility for extracting the format positions, which uses the RustPython string parser underneath and so is very robust. Sorry that I didn't flag this earlier -- I didn't realize it could even be reused here, but it should make things more efficient too since we can do one string parse and share that "summary" amongst a bunch of checks.
contents, | ||
expr.location, | ||
expr.end_location.unwrap(), | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like one strategy that could work here would be...
- Take the entire text.
- Replace the string part via the regex above.
- Replace the arguments via LibCST.
Kinda tough, hacky, etc... but would solve the missing cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I guess that wouldn't solve the '{' '0}'.format(1)
case.
Thanks for the review! |
[![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.217` -> `^0.0.218` | [![age](https://badges.renovateapi.com/packages/pypi/ruff/0.0.218/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/ruff/0.0.218/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/ruff/0.0.218/compatibility-slim/0.0.217)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/ruff/0.0.218/confidence-slim/0.0.217)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>charliermarsh/ruff</summary> ### [`v0.0.218`](https://togithub.com/charliermarsh/ruff/releases/tag/v0.0.218) [Compare Source](https://togithub.com/charliermarsh/ruff/compare/v0.0.217...v0.0.218) #### What's Changed - Implement flake8-simplify SIM112 by [@​messense](https://togithub.com/messense) in [astral-sh/ruff#1764 - Do not autofix PT004 and PT005 by [@​harupy](https://togithub.com/harupy) in [astral-sh/ruff#1763 - Disable release builds on CI by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#1761 - Move CONTRIBUTING.md to top-level by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#1768 - \[`flake8-bandit`] Add Rule for `S508` (snmp insecure version) & `S509` (snmp weak cryptography) by [@​saadmk11](https://togithub.com/saadmk11) in [astral-sh/ruff#1771 - Generate RuleCode::origin() via macro by [@​not-my-profile](https://togithub.com/not-my-profile) in [astral-sh/ruff#1770 - Disable doctests by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#1772 - Enable isort-style `required-imports` enforcement by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#1762 - Pyupgrade: Format specifiers by [@​colin99d](https://togithub.com/colin99d) in [astral-sh/ruff#1594 - Avoid B023 false-positives for some common builtins by [@​charliermarsh](https://togithub.com/charliermarsh) in [astral-sh/ruff#1776 **Full Changelog**: astral-sh/ruff@v0.0.217...v0.0.218 </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:eyJjcmVhdGVkSW5WZXIiOiIzNC45Ny4xIiwidXBkYXRlZEluVmVyIjoiMzQuOTcuMSJ9--> Signed-off-by: Renovate Bot <bot@renovateapp.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
A part of #827. Posting this for visibility. Still has some work to do to be done.
Things that still need done before this is ready:
Tests from pyupgrade can be seen here: https://github.com/asottile/pyupgrade/blob/main/tests/features/format_literals_test.py