Skip to content

Commit

Permalink
Experimental support for import sorting via ruff-api
Browse files Browse the repository at this point in the history
[ghstack-poisoned]
  • Loading branch information
amyreese committed May 2, 2024
1 parent f4ff723 commit 6b158ef
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 5 deletions.
2 changes: 1 addition & 1 deletion docs/guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Options available are described as follows:
[tool.ufmt]
sorter = "usort"
See :class:`~ufmt.types.Formatter` for list of supported choices.
See :class:`~ufmt.types.Sorter` for list of supported choices.


Integrations
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dependencies = [

[project.optional-dependencies]
ruff = [
"ruff-api>=0.0.1",
"ruff-api>=0.0.5",
]
dev = [
"attribution==1.7.1",
Expand Down
22 changes: 20 additions & 2 deletions ufmt/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from moreorless import unified_diff
from trailrunner import Trailrunner
from usort import usort
from usort.config import CAT_FIRST_PARTY, CAT_STANDARD_LIBRARY

try:
import ruff_api
Expand Down Expand Up @@ -107,6 +108,23 @@ def ufmt_bytes(
if result.error:
raise result.error
content = result.output
elif ufmt_config.sorter == Sorter.ruff_api:
ruff_isort_options = ruff_api.SortOptions(
first_party_modules=[
imp
for imp, category in usort_config.known.items()
if category == CAT_FIRST_PARTY
],
standard_library_modules=[
imp
for imp, category in usort_config.known.items()
if category == CAT_STANDARD_LIBRARY
],
)
content_str = ruff_api.isort_string(
path.as_posix(), content.decode(encoding), options=ruff_isort_options
)
content = content_str.encode(encoding)
elif ufmt_config.sorter == Sorter.skip:
pass
else:
Expand All @@ -127,7 +145,7 @@ def ufmt_bytes(
except black.report.NothingChanged:
content = result.output
elif ufmt_config.formatter == Formatter.ruff_api:
options = ruff_api.FormatOptions(
ruff_format_options = ruff_api.FormatOptions(
target_version=str(
black_config.target_versions.pop()
if black_config.target_versions
Expand All @@ -137,7 +155,7 @@ def ufmt_bytes(
preview=black_config.preview,
)
content_str = ruff_api.format_string(
path.as_posix(), content_str, options=options
path.as_posix(), content_str, options=ruff_format_options
)
else:
raise ValueError(f"{ufmt_config.formatter!r} is not a supported formatter")
Expand Down
18 changes: 17 additions & 1 deletion ufmt/tests/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ def test_ufmt_bytes_alternate_formatter(
black_mock.assert_not_called()

@patch("ufmt.core.usort", wraps=usort.usort)
def test_ufmt_bytes_alternate_sorter(self, usort_mock: Mock) -> None:
@patch("ufmt.core.ruff_api.isort_string", wraps=ruff_api.isort_string)
def test_ufmt_bytes_alternate_sorter(
self, ruff_mock: Mock, usort_mock: Mock
) -> None:
black_config = BlackConfig()
usort_config = UsortConfig()

Expand Down Expand Up @@ -249,6 +252,19 @@ def test_ufmt_bytes_alternate_sorter(self, usort_mock: Mock) -> None:
self.assertEqual(CORRECTLY_FORMATTED_CODE.encode(), result)
usort_mock.assert_called_once()

with self.subTest("ruff-api"):
usort_mock.reset_mock()
result = ufmt.ufmt_bytes(
Path("foo.py"),
POORLY_FORMATTED_CODE.encode(),
ufmt_config=UfmtConfig(sorter=Sorter.ruff_api),
black_config=black_config,
usort_config=usort_config,
)
self.assertEqual(CORRECTLY_FORMATTED_CODE.encode(), result)
usort_mock.assert_not_called()
ruff_mock.assert_called_once()

with self.subTest("skip"):
usort_mock.reset_mock()
result = ufmt.ufmt_bytes(
Expand Down
12 changes: 12 additions & 0 deletions ufmt/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ class Sorter(Enum):
usort = "usort"
"""Use µsort (default)."""

ruff_api = "ruff-api"
"""
**Experimental:**
Use Ruff's isort lint rules via unofficial
`ruff-api <https://pypi.org/project/ruff-api>`_ extension.
.. note::
This implementation still depends on and uses the ``[tool.usort]`` configuration
table from ``pyproject.toml`` rather than Ruff's own configuration options.
This may change in future updates.
"""


@dataclass
class UfmtConfig:
Expand Down

0 comments on commit 6b158ef

Please sign in to comment.