Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions docs/guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,17 @@ The following options are valid for the main ``tool.usort`` table:
Whether to merge sequential imports from the same base module.
See `Merging`_ for details on how this works.

.. attribute:: line_length
:type: int
:value: 88

The maximum line length µsort should target when rendering imports. Imports
that fit within this limit, including indentation and inline comments, will
collapse to a single line. Longer imports render as multi-line imports with
one name per line. When both ``[tool.usort]`` ``line_length`` and
``[tool.black]`` ``line-length`` are provided, the value from Black takes
precedence.

.. attribute:: excludes
:type: List[str]

Expand Down Expand Up @@ -597,10 +608,11 @@ as adding the :mod:`example` module to the "first_party" category:
:type: int
:value: 88

The target line length configured for Black will also be used by µsort when
rendering imports after merging and sorting. Imports that fit within this length,
including indentation and comments, will be rendered on a single line. Otherwise,
imports will be rendered as multi-line imports, with a single name per line.
The target line length configured for Black takes precedence over
``[tool.usort]`` ``line_length``. µsort uses this value when rendering imports
after merging and sorting. Imports that fit within this length, including
indentation and comments, will be rendered on a single line. Otherwise, imports
will be rendered as multi-line imports, with a single name per line.

.. _Black: https://black.readthedocs.io

Expand Down
3 changes: 2 additions & 1 deletion docs/why.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ developers writing code:

- No support for configuring output style. µsort works best when run before a
dedicated code formatter like `Black`_ for enforcing style choices. µsort does use
the configured line length for Black when rendering imports on one or more lines.
its configured line length when rendering imports on one or more lines, honoring
``[tool.usort]`` ``line_length`` unless ``[tool.black]`` ``line-length`` is present.
We use `µfmt`_ to combine µsort and Black into a single, atomic formatting step.

- No vendored code. All dependencies are satisfied from PyPI, with unbound version
Expand Down
4 changes: 4 additions & 0 deletions usort/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ def update_from_config(self, toml_path: Path) -> None:
self.merge_imports = bool(tbl["merge_imports"])
if "excludes" in tbl:
self.excludes = tbl["excludes"]
if "line_length" in tbl:
self.line_length = int(tbl["line_length"])
elif "line-length" in tbl:
self.line_length = int(tbl["line-length"])

for cat, names in tbl.get("known", {}).items():
typed_cat = Category(cat)
Expand Down
25 changes: 24 additions & 1 deletion usort/tests/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def test_config_excludes(self) -> None:
expected = ["fixtures/", "*generated.py"]
self.assertEqual(expected, conf.excludes)

def test_black_line_length(self) -> None:
def test_line_length_config_precedence(self) -> None:
with tempfile.TemporaryDirectory() as d:
d_path = Path(d)
(d_path / "foo").mkdir(parents=True)
Expand All @@ -249,6 +249,16 @@ def test_black_line_length(self) -> None:
conf = Config.find(d_path / "foo" / "bar.py")
self.assertEqual(Config.line_length, conf.line_length)

with self.subTest("with usort config"):
(d_path / "foo" / "pyproject.toml").write_text(
"""\
[tool.usort]
line_length = 120
"""
)
conf = Config.find(d_path / "foo" / "bar.py")
self.assertEqual(120, conf.line_length)

with self.subTest("with black config"):
(d_path / "foo" / "pyproject.toml").write_text(
"""\
Expand All @@ -259,6 +269,19 @@ def test_black_line_length(self) -> None:
conf = Config.find(d_path / "foo" / "bar.py")
self.assertEqual(120, conf.line_length)

with self.subTest("black overrides usort"):
(d_path / "foo" / "pyproject.toml").write_text(
"""\
[tool.usort]
line_length = 120

[tool.black]
line-length = 90
"""
)
conf = Config.find(d_path / "foo" / "bar.py")
self.assertEqual(90, conf.line_length)

def test_config_parent_walk(self) -> None:
with tempfile.TemporaryDirectory() as d:
d_path = Path(d)
Expand Down