Skip to content

lint.future-annotations = true causes TC001/TC002/TC003 to act like lint.flake8-type-checking.strict #23185

Description

@Avasam

Summary

https://docs.astral.sh/ruff/settings/#lint_flake8-type-checking_strict states

Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module.

But enabling https://docs.astral.sh/ruff/settings/#lint_future-annotations causes at least TC001/TC002/TC003 to also act that way. Which is unexpected.

I do want to add from __future__ import annotations rather than quoting annotations in code, but I also want my imports to stay on one line if there's a runtime import

Image

Version

ruff 0.15.0

ruff.toml:

[lint]
future-annotations = true # Enable adding `from __future__ import annotations`
extend-select = [
	# upstream

	"C901", # complex-structure
	"I", # isort
	"PERF401", # manual-list-comprehension

	# Ensure modern type annotation syntax and best practices
	# Not including those covered by type-checkers or exclusive to Python 3.11+
	"FA", # flake8-future-annotations
	"F404", # late-future-import
	"PYI", # flake8-pyi
	"UP006", # non-pep585-annotation
	"UP007", # non-pep604-annotation
	"UP010", # unnecessary-future-import
	"UP035", # deprecated-import
	"UP037", # quoted-annotation
	"UP043", # unnecessary-default-type-args

	# local
	"ANN2", # missing-return-type-*
	"ISC", # flake8-implicit-str-concat
	"FURB", # refurb
	"PERF", # Perflint
	"PIE", # flake8-pie
	"PGH", # pygrep-hooks (blanket-* rules)
	"PT", # flake8-pytest-style
	"RUF10", # unused-noqa & redirected-noqa
	"TRY", # tryceratops
	"UP", # pyupgrade
	"YTT", # flake8-2020
	# Helps prevent circular imports, reduce runtime cost of typing symbols,
	# and prevent leaking implementations details into modules
  	"TC", # flake8-type-checking
]
ignore = [
	# upstream

	# Typeshed rejects complex or non-literal defaults for maintenance and testing reasons,
	# irrelevant to this project.
	"PYI011", # typed-argument-default-in-stub
	# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
	"W191",
	"E111",
	"E114",
	"E117",
	"D206",
	"D300",
	"Q000",
	"Q001",
	"Q002",
	"Q003",
	"COM812",
	"COM819",

	# local
	"PERF203", # try-except-in-loop, micro-optimisation with many false-positive. Worth checking but don't block CI
	"PT007", # temporarily disabled, TODO: configure and standardize to preference
	"PT011", # temporarily disabled, TODO: tighten expected error 
	"PT012", # pytest-raises-with-multiple-statements, avoid extra dummy methods for a few lines, sometimes we explicitly assert in case of no error
	"TRY003", # raise-vanilla-args, avoid multitude of exception classes
	"TRY301", # raise-within-try, it's handy
	"UP015", # redundant-open-modes, explicit is preferred
	# Only enforcing return type annotations for public functions
	"ANN202", # missing-return-type-private-function
	# stdlib is not at risk of circular import, is clearly not public API,
	# and assume it's gonna be included in the import chain at some point anyway 
  	"TC003", # typing-only-standard-library-import
]

[lint.per-file-ignores]
# Suppress nuisance warnings about module-import-not-at-top-of-file (E402) due to workaround for #4476
"setuptools/__init__.py" = ["E402"]

[lint.isort]
combine-as-imports = true
split-on-trailing-comma = false
# Force Ruff/isort to always import setuptools before distutils in tests as long as distutils_hack is supported
# This also ensures _distutils_hack is imported before distutils
# https://github.com/pypa/setuptools/issues/4137
section-order = ["future", "standard-library", "eager", "third-party", "first-party", "local-folder", "delayed"]
sections.eager = ["_distutils_hack"]
sections.delayed = ["distutils"]

[lint.flake8-annotations]
ignore-fully-untyped = true

[lint.flake8-type-checking]
quote-annotations = true

[format]
# Enable preview to get hugged parenthesis unwrapping and other nice surprises
# See https://github.com/jaraco/skeleton/pull/133#issuecomment-2239538373
preview = true
# https://docs.astral.sh/ruff/settings/#format_quote-style
quote-style = "preserve"

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinghelp wantedContributions especially welcome

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions