We've observed an odd behavior where the extend-select = ["I"] is not honored for code in tests/ when a very specific set of circumstances occur. I'm not even sure I have the minimum reproduction steps completely down, but I can very consistently reproduce the situation.
- The tests import items from specific module
mod1
- The python code structure starts at
src instead of the repo root
- A directory
mod1 exists at the repo root. This directory can be empty
- This is the most bizarre part: This depends on the contents of the test files
tests/test_mod1.py. Modifying the file contents can in some cases cause extend-select from pyproject.toml to be respected. Some of these are very insignificant changes, like insertion of a comment between imports, removal of a blank line between imports, etc.
- Run
ruff check --no-cache and observe that tests/test_mod1.py is not checked for I001 as requested in pyproject.toml. Be sure to use --no-cache during tests because some actions will not invalidate the cache that otherwise would, like creating/removing the top-level mod1 directory.
The minimum reproduction is below, but is also available as a git repository https://github.com/jamesharr/ruff-issue-12453
This bug was initially spotted due to a dirty working directory, and we eventually narrowed it down to an empty to-level folder that matches one of the modules a test imports. Of course git ignores empty directories, so we were chasing our tails on this one for a few days.
Ruff version: ruff 0.5.4 on macOS 14.5, though we've also seen it with 0.5.2 and 0.5.3
Command: ruff check --no-cache .
Directory structure:
% tree .
.
├── README.md
├── mod1 # Empty directory required for bug reproduction
├── pyproject.toml # Sets "extend-select" to "I"
├── src
│ └── mod1
│ └── __init__.py
└── tests
└── test_mod1.py # File is not always check
5 directories, 4 files
Contents of pyproject.toml
[tool.poetry]
name = "ruff-bug"
version = "0.0.0"
description = "Ruff bug demo project"
authors = []
readme = "README.md"
packages = [
{ include = "mod1", from = "src" },
]
[tool.ruff.lint]
extend-select = ["I"]
Contents of tests/test_mod1.py
def test_bug1():
# For the bug to occur:
# - [repo-root]/mod1 must exist as a directory; contents of directory do not seem to matter
# - There must be an empty line after the first import import
# - It cannot be two blank lines
# - It cannot be line with a comment
# - It can be a line consisting of only tabs/whitespaces
# - All 3 imports must exist and in this order
# - All 3 imports must exist within the function
#
# When the above conditions are met, then tests/* are NOT checked for I001 (unsorted imports)
# as requested in pyproject.toml.
#
# Files in src/* are checked for I001 as requested in pyproject.toml, regardless of the contents
# of this file.
from external_lib import qux
from mod1 import foo
from mod1.bar import baz
# I think the code below is only important because it uses the above imports
print(qux)
print(foo)
print(baz)
% cat src/mod1/__init__.py
# The contents of this file seem to have no bearing bug reproduction
# - I001 seems to always be checked for this file, as specified in pyproject.toml
#
# You can illustrate this by re-ordering these imports
import os
import sys
# The following code only exists to use the imports and avoid F401 (imported but unused)
print(os)
print(sys)
We've observed an odd behavior where the
extend-select = ["I"]is not honored for code intests/when a very specific set of circumstances occur. I'm not even sure I have the minimum reproduction steps completely down, but I can very consistently reproduce the situation.mod1srcinstead of the repo rootmod1exists at the repo root. This directory can be emptytests/test_mod1.py. Modifying the file contents can in some cases causeextend-selectfrompyproject.tomlto be respected. Some of these are very insignificant changes, like insertion of a comment between imports, removal of a blank line between imports, etc.ruff check --no-cacheand observe thattests/test_mod1.pyis not checked forI001as requested inpyproject.toml. Be sure to use--no-cacheduring tests because some actions will not invalidate the cache that otherwise would, like creating/removing the top-levelmod1directory.The minimum reproduction is below, but is also available as a git repository https://github.com/jamesharr/ruff-issue-12453
This bug was initially spotted due to a dirty working directory, and we eventually narrowed it down to an empty to-level folder that matches one of the modules a test imports. Of course git ignores empty directories, so we were chasing our tails on this one for a few days.
Ruff version:
ruff 0.5.4on macOS 14.5, though we've also seen it with 0.5.2 and 0.5.3Command:
ruff check --no-cache .Directory structure:
Contents of
pyproject.tomlContents of
tests/test_mod1.py