Search code examples
pythonpre-commit-hookruff

How do I stop the ruff linter from moving imports into a TYPE CHECKING if block?


I have a pydantic basemodel that looks something like:

from pathlib import Path
from pydantic import BaseModel


class Model(BaseModel):
    log_file: Path

And my ruff pre-commit hook is re-ordering it to:

from typing import TYPE_CHECKING
from pydantic import BaseModel

if TYPE_CHECKING:
    from pathlib import Path


class Model(BaseModel):
    log_file: Path

Which is then causing the bug:

pydantic.errors.ConfigError: field "log_file" not yet prepared so type is still a ForwardRef, you might need to call Model.update_forward_refs()

Which I dont want to do. How can I stop ruff from re-ordering the imports like this? My .pre-commit-config.yaml file looks like:

repos:
  - repo: https://github.com/charliermarsh/ruff-pre-commit
    rev: "v0.0.291"
    hooks:
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]
  - repo: https://github.com/psf/black
    rev: 23.9.1
    hooks:
      - id: black
        language_version: python3

and my pyproject.toml file:

[tool.black]
line-length = 120
include = '\.pyi?$'
exclude = '''
/(
    \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | _build
  | buck-out
  | build
  | dist
  # The following are specific to Black, you probably don't want those.
  | blib2to3
  | tests/data
  | profiling
)/
'''


[tool.ruff]
line-length = 120
ignore = ["F405", "B008"]
select = ["E", "F", "B", "C4", "DTZ", "PTH", "TCH", "I001"]
# unfixable = ["C4", "B"]
exclude = ["docs/conf.py", "Deployment/make_deployment_bundle.py"]

[tool.ruff.per-file-ignores]
"**/__init__.py" = ["F401", "F403"]

[tool.ruff.isort]
split-on-trailing-comma = true
known-first-party = ["influxabart"]
no-lines-before = ["local-folder"]

section-order = ["future","standard-library","third-party","first-party","this","local-folder"]

[tool.ruff.isort.sections]
"this" = ["InfluxTools"]

Solution

  • Haven't reproduced this, but I think your list of select options is causing this. I know that this isn't the default behaviour of ruff.

    select = ["E", "F", "B", "C4", "DTZ", "PTH", "TCH", "I001"]
    

    Even though the official readme says TC* is the code for flake8-type-checking, this issue hints that TCH* is.

    From the README:

    TC001   Move application import into a type-checking block
    TC002   Move third-party import into a type-checking block
    TC003   Move built-in import into a type-checking block
    

    So TC003 is what's happening to you. Or TCH003 is what I'm guessing ruff calls it.

    So I think the solution is to remove that "TCH" field from the select in your pyproject.toml.