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

Allow formatting with ruff instead of black #58

Open
alexmojaki opened this issue Mar 25, 2024 · 12 comments
Open

Allow formatting with ruff instead of black #58

alexmojaki opened this issue Mar 25, 2024 · 12 comments

Comments

@alexmojaki
Copy link

Every time I fix snapshots, I immediately have to press a few more keys to reformat with ruff. It'd be lovely if it was already formatted 'correctly'.

@15r10nk
Copy link
Owner

15r10nk commented Mar 25, 2024

It preserves currently the black formatting (https://15r10nk.github.io/inline-snapshot/#code-generation point 5).

I think the problem is that it does not detect that your code is formatted with "black style".
black and ruff should format the code in the similar 99% like way.

Maybe your files are part of this 1%, or there are some black or ruff options which are responsible for the different formatting.

Maybe this info helps you.

The other option for me would be to preform the same check and formatting with ruff, which I do with black.

@alexmojaki
Copy link
Author

  1. Something is wrong with the black formatting and indentation.
  2. We use single quotes for strings, so ruff and black format differently.
$ cat /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py                         
from inline_snapshot import snapshot


def test_example():
    foo = [dict.fromkeys(range(6), 'abcdefghijkl') for _ in range(2)]
    assert foo == snapshot(0)

$ pytest --inline-snapshot=fix /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py
=============================================================================== test session starts ===============================================================================
platform linux -- Python 3.12.1, pytest-7.4.3, pluggy-1.3.0
rootdir: /home/alex
plugins: xdist-3.5.0, anyio-4.2.0, base-url-2.0.0, hypothesis-6.92.2, logfire-0.22.0, playwright-0.4.3, devtools-0.12.2, inline-snapshot-0.7.0, django-4.8.0, timeout-2.2.0, requests-mock-1.11.0, pretty-1.2.0
collected 1 item                                                                                                                                                                  

../../.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py .                                                                                                           [100%]
================================================================================= inline snapshot =================================================================================
fixed 1 snapshots
Results (0.15s):
         1 passed

$ cat /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py
from inline_snapshot import snapshot


def test_example():
    foo = [dict.fromkeys(range(6), 'abcdefghijkl') for _ in range(2)]
    assert foo == snapshot([
    {
        0: "abcdefghijkl",
        1: "abcdefghijkl",
        2: "abcdefghijkl",
        3: "abcdefghijkl",
        4: "abcdefghijkl",
        5: "abcdefghijkl",
    },
    {
        0: "abcdefghijkl",
        1: "abcdefghijkl",
        2: "abcdefghijkl",
        3: "abcdefghijkl",
        4: "abcdefghijkl",
        5: "abcdefghijkl",
    },
])

$ black /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py
reformatted /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py

All done! ✨ 🍰 ✨
1 file reformatted.

$ cat /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py
from inline_snapshot import snapshot


def test_example():
    foo = [dict.fromkeys(range(6), "abcdefghijkl") for _ in range(2)]
    assert foo == snapshot(
        [
            {
                0: "abcdefghijkl",
                1: "abcdefghijkl",
                2: "abcdefghijkl",
                3: "abcdefghijkl",
                4: "abcdefghijkl",
                5: "abcdefghijkl",
            },
            {
                0: "abcdefghijkl",
                1: "abcdefghijkl",
                2: "abcdefghijkl",
                3: "abcdefghijkl",
                4: "abcdefghijkl",
                5: "abcdefghijkl",
            },
        ]
    )

$ ruff format /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py
1 file reformatted

$ cat /home/alex/.config/JetBrains/PyCharm2023.3/scratches/scratch_1906.py
from inline_snapshot import snapshot


def test_example():
    foo = [dict.fromkeys(range(6), 'abcdefghijkl') for _ in range(2)]
    assert foo == snapshot(
        [
            {
                0: 'abcdefghijkl',
                1: 'abcdefghijkl',
                2: 'abcdefghijkl',
                3: 'abcdefghijkl',
                4: 'abcdefghijkl',
                5: 'abcdefghijkl',
            },
            {
                0: 'abcdefghijkl',
                1: 'abcdefghijkl',
                2: 'abcdefghijkl',
                3: 'abcdefghijkl',
                4: 'abcdefghijkl',
                5: 'abcdefghijkl',
            },
        ]
    )

@15r10nk
Copy link
Owner

15r10nk commented Mar 25, 2024

The problem is that ruff formats differently than black in your case (double/single quotes).

inline-snapshot looks at the source before it changes anything and thinks "this is not formatted with black". It re-formats only the snapshots with black (this causes the double quotes in your snapshots) and skips the reformatting of the whole file.

I think you have

[tool.ruff.format]
quote-style = "single"

in your config.

I will think about a way to handle the formatting better. Maybe a enforce-format="black|ruff" option, maybe integrating ruff in the same way I integrated black.

What would you prefer?

@alexmojaki
Copy link
Author

OK, I see now how this happens:

def test_example():
    foo = [dict.fromkeys(range(6), 'abcdefghijkl') for _ in range(2)]
    assert foo == snapshot([
    {
        0: "abcdefghijkl",
        1: "abcdefghijkl",
        2: "abcdefghijkl",
        3: "abcdefghijkl",
        4: "abcdefghijkl",
        5: "abcdefghijkl",
    },
    {
        0: "abcdefghijkl",
        1: "abcdefghijkl",
        2: "abcdefghijkl",
        3: "abcdefghijkl",
        4: "abcdefghijkl",
        5: "abcdefghijkl",
    },
])

as a result of only formatting the snapshot. I do think that could be improved so that the result is still nice for people who are not using any kind of formatter. Specifically, I think you should black/ruff-format the snapshot call node (not just the contents) and then indent that by the amount of indentation in the containin statement (4 spaces in this case).

I will think about a way to handle the formatting better. Maybe a enforce-format="black|ruff" option, maybe integrating ruff in the same way I integrated black.

What would you prefer?

I'm not sure I understand the difference between the two options. If both are integrated, there will probably need to be a config option to pick one. You could maybe default to using the one that seems closest to the file's current formatting. If it's a tie, I would suggest choosing ruff just because it's faster.

@15r10nk
Copy link
Owner

15r10nk commented Mar 26, 2024

Formating source ranges is not supported by black psf/black#134 (comment)

I can fix the indentation and make it look acceptable if you are not using black for your whole file. But the indentation affects the formatting and this solution will probably never be perfect.

Detecting if a file is formatted and preserving this formatting is easier. This is what inline-snapshot currently does with black.

You can format your example with black before you fix your snapshot. Inline-snapshot will format the whole file after the fix and preserve the formatting.

I think I can implement the same behavior for ruff formatted files.

@alexmojaki
Copy link
Author

To be clear, for the case of formatting just the snapshot, I'm only talking about it for the sake of interest and because I imagine you'd like it to work better for users not using black/ruff. I'm happy with just formatting the whole file with ruff.

I'm not suggesting formatting source ranges. I'm saying instead of using black to format [{...}], format snapshot([{...}]), and then indent that.

@hynek
Copy link

hynek commented Sep 5, 2024

BTW, it would be nice to use inline-snapshot completely without Black since it pulls in several the dependencies.

Wouldn't it be reasonable to tell users that whatever code formatter they use, it should be installed for this to work? Would probably require a major bump, but then again it's "just" a test dependency so no service should go down because of that. Maybe add inline-snapshots[black] and inline-snapshots[ruff], too.

@15r10nk
Copy link
Owner

15r10nk commented Sep 5, 2024

@hynek, you propose to ship inline-snapshot without a default formatter, if I understand you correct.

The problem is that repr() has no line length limit or formatting. It generates just an very long string when you pass it some large dict/list values. This is not the best experience for the developer.

But it might be a good idea to provide only a inline-snapshots[ruff] option which depends not on black.

@hynek
Copy link

hynek commented Sep 5, 2024

Yeah, I personally would be fine with Black being the default, but not being auto-installed. And that I’m able to overwrite the default in tool.inline-snapshot.formatter or something like that.

@pawamoy
Copy link
Contributor

pawamoy commented Dec 20, 2024

Like @hynek I'd prefer to be in control. I use Ruff and my config file is located in a subfolder anyway, so running Ruff automatically won't find the config file, and will use different formatting options (the default ones). Having a config option to specify the command to run would be ideal:

[tool.inline-snapshot]
format_command = "ruff format --config=config/ruff.toml {}"

...where {} gets replaced by the list of files to format, maybe.

Though maybe you're currently running Black from Python, not with a subprocess, so this might complicate things. Not critical to me, I'm even happy to just run Ruff myself after tests were changed 🙂

@15r10nk
Copy link
Owner

15r10nk commented Dec 20, 2024

Having a config option to specify the command to run would be ideal

I like the idea. This gives the user the maximal control about the formatting.

@hynek
Copy link

hynek commented Dec 21, 2024

still time until xmaaaassss! 🎁🎄🎁🎅😇

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

No branches or pull requests

4 participants