Skip to content

group-imports

group-imports moves each import in a contiguous run into its canonical section, a from __future__ import ahead of everything, then the bare import statements, the external from … import … statements, and the local-package imports last:

SectionMembers
__future__from __future__ import annotations
Bareimport os, import numpy as np
External fromfrom collections import Counter
Local-packagerelative imports and any package on the first-party list

The rule moves imports into their sections and leaves the order within each to alphabetize-siblings, so the two agree on the grouping through one shared classifier. A run already in section order passes through with no edit.

An absolute from __future__ import … takes the leading section on its own, because Python rejects a module that places the statement below any other code, so the section is a compiler requirement rather than a legibility preference. A relative from .__future__ import … and a bare import __future__ name ordinary modules and classify as any other import does.

A from import is local when it is relative (from . import x, from ..pkg import y) or its module's root package appears on the first-party list. A bare import is local when the root package of any name it binds is first-party. Every other bare import stays bare, every other from import is external, and a statement that is no import at all stays where it sits and ends the run.

A recognized section marker (a hand-drawn banner like # --- Typing --- or a ## hash heading) divides a run into independent sections, so an author who grouped imports under a divider keeps that grouping and no import crosses the marker into the section above it. space-statements owns the single blank line between one canonical section and the next, reflow-imports runs afterward and splits a comma-joined statement so each module sits on its own line in its section, and align-imports reads the grouped result and aligns the import keyword within each section.

Configuration

KeyTypeDefaultMeaning
enabledbooltrueTurns the rule on or off.

group-imports is a single on/off toggle, and left on it moves every import run into the canonical sections. Turned off with group-imports = false, the imports read as one flat block and alphabetize-siblings sorts them together rather than within sections. The imports.first-party list under [imports] (see the configuration reference) names the packages that join the local-package section alongside relative imports.

The Canonical Case

A scrambled run mixes bare, external from, and local imports, with myapp named in first-party. group-imports partitions the run into bare, external from, and local sections in that order, so import sys and import os lead, from typing import Any and from collections import Counter follow, and from myapp import app and from . import shared close the run.

Within a section the statements keep their source order, so sys stays ahead of os, because sorting belongs to alphabetize-siblings and the blank line between sections to space-statements.

import sys
import os
from typing import Any
from collections import Counter
from myapp import app
from . import shared
python

More Examples

The # --- Local --- comment sits between import sys and from . import shared. Each side of the banner partitions on its own and no import crosses it, so import sys moves above from collections import Counter in the upper section, and import os moves above from . import shared in the lower one rather than joining import sys.

Under if TYPE_CHECKING:, from collections import abc sits above import sys. group-imports moves the bare import sys above the from import in place, both lines keeping the arm's indent, because the rule reads the body of a compound statement the same way it reads the module.

The body of load opens with from collections import Counter above import sys. group-imports moves the bare import sys above the from import in place, both lines keeping the function-body indent, because the rule reads every nested body the same way it reads the module.

No Change

With myapp named in first-party, the run already reads bare imports, then the external from collections import Counter, then the first-party from myapp import app. group-imports emits no edit, because every statement already sits in its section and the rule rewrites only when a statement has to move.

  1. import sys, os and import myapp.core, abc each name two modules in one statement, with myapp in first-party. reflow-imports splits each into one module per line ahead of group-imports and alphabetize-siblings, so every split-off module reaches its own group and its sorted position, and myapp.core ends up in the local section rather than beside the stdlib abc it was joined to.

  2. Bare, external from, and local imports sit scrambled together, with myapp named in first-party. group-imports partitions them into bare, external, and local sections, alphabetize-siblings sorts the names within each section, space-statements writes one blank line between sections, and align-imports pads the import keyword into a column within each section.