astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.
https://docs.astral.sh/ruff
MIT License
31.06k stars 1.03k forks source link

Different length sort behavior against isort #9870

Open yanyongyu opened 7 months ago

yanyongyu commented 7 months ago

I'm trying to migrate isort and black to ruff but encountered some problems when using ruff's isort configs.

Ruff version 0.2.1.

Suppose I have a first-party package named package and the test code is:

from package.utils import a
from package.func import function

with the ruff config:

[tool.ruff.lint]
select = ["I"]

[tool.ruff.lint.isort]
length-sort = true
force-sort-within-sections = true

ruff will report import order error and fix it into:

from package.func import function
from package.utils import a

but isort sorts it as the origin test code given above.

I make one more test, renaming the package.func to package.function:

from package.utils import a
from package.function import function

this time ruff does not report any error. It seems ruff sort the import order by module name length instead of import expression length?

charliermarsh commented 7 months ago

Can you clarify for me -- if I run isort over:

from package.utils import a
from package.func import function

With length_sort = true, it rewrites to:

from package.func import function
from package.utils import a

In my testing, Ruff has the same behavior. But it seems like you're seeing different behavior with isort?

yanyongyu commented 7 months ago

i sort the code with: (isort 5.13.2)

isort --profile black --length-sort --force-sort-within-sections package/__init__.py
yanyongyu commented 7 months ago

Or use the pyproject.toml to config isort:

[tool.ruff.lint]
select = ["I"]

[tool.ruff.lint.isort]
length-sort = true
force-sort-within-sections = true

[tool.isort]
profile = "black"
length_sort = true
force_sort_within_sections = true

then sort the imports with isort .

the output code is:

from package.utils import a
from package.func import function
charliermarsh commented 7 months ago

It this an isort bug? Removing --force-sort-within-sections shows the same behavior as Ruff, but I don't see why --force-sort-within-sections should have an effect on the sort in this case (both imports are in the same section).

yanyongyu commented 7 months ago

Isort docs: Length Sort: Sort imports by their string length. Force Sort Within Sections: Instead, sort the imports by module, independent of import style.

I'm not sure which behavior is correct 😂 , but isort keeps this behavior for years.

charliermarsh commented 7 months ago

Haha :)

I looked through the isort source. It looks like if --force-sort-within-sections is set, it sorts all lines by their exact length. If it's not set, it sorts by the length of the module, then sorts each member by length. So the behavior is totally different when that flag is set. I find it confusing... But if we don't support it, we may want to document it at least.

tomprimozic commented 6 months ago

I'd also want a "sort imports by line length exactly" with no extra exceptions. isort does (almost) support that (except some edge cases / bugs) using length_sort and force_sort_within_sections options, it would be great if ruff did as well.

For the time being, I have to use 2 tools :/

yanyongyu commented 5 months ago

@charliermarsh Is there any decision about this issue? Currently, i also have to use 2 tools (isort + ruff) to lint and format the code. i hope this feature can be part of this excellent project. :pray:

rainzee commented 5 months ago

This is really the last hurdle for me to fully use ruff, now I have to use both tools, hopefully some progress will be made, please!🙏

forchannot commented 3 months ago

any progress on this issue?