diff --git a/docs/linting.rst b/docs/linting.rst
index 27c3ca5..e6c031b 100644
--- a/docs/linting.rst
+++ b/docs/linting.rst
@@ -15,7 +15,6 @@ The template's configuration installs and runs the following tools automatically
* **zizmor** -- scans GitHub Actions workflow files for security issues.
* **ruff** -- lints and auto-fixes Python files (see below).
-* **isort** -- sorts import statements (see below).
* **pre-commit-hooks** -- a suite of basic sanity checks: valid Python syntax, valid YAML/TOML, no trailing whitespace, no debug statements, no large files, consistent line endings, and end-of-file newlines.
* **codespell** -- checks for common spelling mistakes (see below).
@@ -36,7 +35,7 @@ To have pre-commit automatically run the checks when you make a commit locally r
Ruff
----
-`Ruff `__ is a fast Python linter that replaces flake8, pyupgrade, isort (partially), and numerous other tools.
+`Ruff `__ is a fast Python linter that replaces flake8, pyupgrade, isort, and numerous other tools.
The template configures a base rule set covering pycodestyle errors and warnings, pyflakes, pyupgrade, and pytest-style rules.
The ``use_extended_ruff_linting`` option (see :doc:`new_package_options`) enables additional rule sets for bugbear, blind-except, comprehensions, implicit namespace packages, print statements, return statements, tidy imports, pathlib usage, pandas idioms, pylint conventions and errors, flynt, numpy, performance, and ruff-specific checks.
@@ -48,17 +47,6 @@ Per-file ignores relax import-ordering and unused-import rules in ``__init__.py`
See the ``.ruff.toml`` file in your repository for more information about what is configured.
-isort
------
-
-`isort `__ sorts Python imports into grouped sections.
-The template defines a custom section order that separates astropy ecosystem packages (``astropy``, ``asdf``) and SunPy packages (``sunpy``) from generic third-party imports, so imports from the scientific Python ecosystem are visually distinct.
-
-.. note::
-
- See https://github.com/sunpy/package-template/issues/230 for details on why we haven't (yet) replaced isort with ruff.
-
-
Codespell
---------
diff --git a/{{ cookiecutter.package_name }}/.isort.cfg b/{{ cookiecutter.package_name }}/.isort.cfg
deleted file mode 100644
index 269e6be..0000000
--- a/{{ cookiecutter.package_name }}/.isort.cfg
+++ /dev/null
@@ -1,16 +0,0 @@
-[settings]
-balanced_wrapping = true
-skip =
- docs/conf.py
- {{ cookiecutter.module_name }}/__init__.py
-default_section = THIRDPARTY
-include_trailing_comma = true
-known_astropy = astropy, asdf
-known_sunpy = sunpy
-known_first_party = {{ cookiecutter.module_name }}
-length_sort = false
-length_sort_sections = stdlib
-line_length = 110
-multi_line_output = 3
-no_lines_before = LOCALFOLDER
-sections = STDLIB, THIRDPARTY, ASTROPY, SUNPY, FIRSTPARTY, LOCALFOLDER
diff --git a/{{ cookiecutter.package_name }}/.pre-commit-config.yaml b/{{ cookiecutter.package_name }}/.pre-commit-config.yaml
index c4b7b0f..e9b7ac1 100644
--- a/{{ cookiecutter.package_name }}/.pre-commit-config.yaml
+++ b/{{ cookiecutter.package_name }}/.pre-commit-config.yaml
@@ -12,12 +12,6 @@ repos:
types: [python]
# Define here once and then reference using YAML anchor
exclude: &exclude_dirs ^{{ cookiecutter.module_name }}/(data|extern)/
- - repo: https://github.com/PyCQA/isort
- rev: 8.0.1
- hooks:
- - id: isort
- types: [python]
- exclude: *exclude_dirs
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
diff --git a/{{ cookiecutter.package_name }}/.ruff.toml b/{{ cookiecutter.package_name }}/.ruff.toml
index 94e2d2c..9497889 100644
--- a/{{ cookiecutter.package_name }}/.ruff.toml
+++ b/{{ cookiecutter.package_name }}/.ruff.toml
@@ -14,6 +14,7 @@ select = [
"W",
"UP",
"PT",
+ "I",
{%- if cookiecutter.use_extended_ruff_linting == 'y' %}
"BLE",
"A",
@@ -58,7 +59,8 @@ extend-ignore = [
"INP001", # File is part of an implicit namespace package.
]
"docs/conf.py" = [
- "E402" # Module imports not at top of file
+ "E402", # Module imports not at top of file
+ "I", # isort
]
"docs/*.py" = [
"INP001", # File is part of an implicit namespace package.
@@ -72,6 +74,7 @@ extend-ignore = [
"F401", # Unused import
"F403", # from {name} import * used; unable to detect undefined names
"F405", # {name} may be undefined, or defined from star imports
+ "I", # isort
]
"test_*.py" = [
"E402", # Module level import not at top of cell
@@ -79,3 +82,27 @@ extend-ignore = [
[lint.pydocstyle]
convention = "numpy"
+
+[lint.isort]
+default-section = "third-party"
+section-order = [
+ "future",
+ "standard-library",
+ "third-party",
+ "astropy",
+{%- if cookiecutter.module_name != "sunpy" %}
+ "sunpy",
+{%- endif %}
+ "first-party",
+ "local-folder",
+]
+{%- if cookiecutter.module_name != "sunpy" %}
+known-first-party = ["{{ cookiecutter.module_name }}"]
+{%- endif %}
+no-lines-before = ["local-folder"]
+
+[lint.isort.sections]
+"astropy" = ["astropy", "asdf", "gwcs", "reproject"]
+{%- if cookiecutter.module_name != "sunpy" %}
+"sunpy" = ["sunpy"]
+{%- endif %}