# pyfltr
> Python Formatters, Linters, and Testers Runner
# ホーム
# pyfltr
Python Formatters, Linters, and Testers Runner
Pythonの各種ツールをまとめて呼び出すツール。
ドキュメント:
llms.txt:
## 対応ツール
- Formatters
- pyupgrade
- autoflake
- isort
- black
- ruff format(既定では無効。有効時は `ruff check --fix --unsafe-fixes` を併走する、`ruff-format-by-check`でOFF可)
- prettier(既定では無効、`js-runner`設定で起動方式を切替可能。`--check`と`--write`の2段階実行)
- uv-sort(既定では無効、`pyproject.toml`の依存ソート)
- shfmt(既定では無効、`bin-runner`設定で起動方式を切替可能。prettierと同様の2段階実行)
- Linters
- ruff check(既定では無効)
- pflake8 + flake8-bugbear + flake8-tidy-imports
- mypy
- pylint
- pyright(既定では無効)
- ty(既定では無効)
- ec(editorconfig-checker。既定では無効、`bin-runner`設定で起動方式を切替可能)
- shellcheck(既定では無効、`bin-runner`設定で起動方式を切替可能)
- typos(既定では無効、`bin-runner`設定で起動方式を切替可能)
- actionlint(既定では無効、`bin-runner`設定で起動方式を切替可能)
- markdownlint-cli2(既定では無効、`js-runner`設定で起動方式を切替可能。既定は`pnpx`)
- textlint(既定では無効、`js-runner`設定で起動方式を切替可能。`textlint-packages`でプリセット/ルール指定)
- eslint(既定では無効、`js-runner`設定で起動方式を切替可能。`--format json`で機械可読出力を取得)
- biome(既定では無効、`js-runner`設定で起動方式を切替可能。`biome check`サブコマンドと`--reporter=github`を使用)
- oxlint(既定では無効、`js-runner`設定で起動方式を切替可能)
- tsc(既定では無効、`js-runner`設定で起動方式を切替可能。`--noEmit`で型チェックのみ実行)
- Testers
- pytest
- vitest(既定では無効、`js-runner`設定で起動方式を切替可能。`run`サブコマンドで実行)
## コンセプト
- 各種ツールをまとめて並列で呼び出し、実行時間を短縮する
- 各種ツールのバージョンには極力依存しない(各ツール固有の設定には対応しない)
- excludeの指定方法が各ツールで異なる問題を、pyfltr側で解決してツールに渡すことで吸収する
- blackやisortはファイルを修正しつつエラーとしても扱う(CI用途などを想定。pyupgradeは本来そのような動作)
- 設定は極力`pyproject.toml`に集約する
## インストール
```
pip install pyfltr
```
# 使い方
# 使い方
## サブコマンド
pyfltrはサブコマンドで動作モードを指定する。
```
pyfltr [files and/or directories ...]
```
対象を指定しなかった場合は、カレントディレクトリを指定した場合と同じ扱いとなる。
指定したファイルやディレクトリの配下のうち、各コマンドのtargetsパターンに一致するファイルのみ処理される。
- Python系ツール: `*.py`
- markdownlint / textlint: `*.md`
- pytest: `*_test.py`
### ci(既定)
```
pyfltr ci [files and/or directories ...]
pyfltr [files and/or directories ...] # ciは省略可能
```
全チェック実行。CI環境やコミット前の検証に適する。
終了コード:
- 0: Formattersによるファイル変更が無く、かつLinters/Testersでのエラーも無い場合
- 1: 上記以外の場合
### run
```
pyfltr run [files and/or directories ...]
```
全チェック実行。Formattersによるファイル変更があってもLinters/Testersでのエラー無しなら終了コードは0になる。ローカルでの全チェック実行に適する。
### fast
```
pyfltr fast [files and/or directories ...]
```
mypy / pylint / pytestなど重いコマンドを除外した軽量チェック。Formattersによるファイル変更があっても終了コードは0になる。pre-commitフックなど速度を優先する場面に適する。
既定で含まれるコマンドは以下。
- Formatters: `pyupgrade` `autoflake` `isort` `black` `ruff-format` `prettier` `uv-sort` `shfmt`
- Linters: `ec` `shellcheck` `typos` `actionlint` `ruff-check` `pflake8` `ty` `markdownlint` `textlint` `biome` `oxlint`
含まれるコマンドは各コマンドの`{command}-fast`設定で制御できる([設定](https://ak110.github.io/pyfltr/guide/configuration/index.md)を参照)。
### fix
```
pyfltr fix [files and/or directories ...]
```
修正モード。linterの中でもautofix機能を持つtextlint / markdownlint / ruff-checkなどに、内部で `--fix` 相当の引数を追加して実行する。手動実行専用。
fixモードの対象は次の和集合となる。
- 有効化されたformatter全て(通常実行そのものがファイルを修正する)
- 有効化されており、かつ `{command}-fix-args` が定義されたlinter(ビルトインではtextlint / markdownlint / ruff-check / eslint / biomeが既定で対応)
fixモードの挙動。
- 全対象コマンドを順次実行する(同一ファイルへの書き込み競合を避けるため並列化しない)
- `--shuffle` は無効化される
- 対象が0件の場合はエラー終了する
- `--commands` と併用可能。併用時は展開後の結果に対して上記フィルタを適用する
- linterのfix実行後、ファイルmtimeの変化があれば `formatted`、変化が無ければ `succeeded`、終了コードが0以外なら `failed` となる
- 特にruff-checkは未修正の違反が残ると終了コード1を返すため、`failed` 扱いとなる。通常モードの `ruff-check` で残存違反を別途確認すること
カスタムコマンドでも `pyproject.toml` の `[tool.pyfltr.custom-commands.]` に `fix-args = [...]` を定義すればfixモードの対象にできる。
## 特定のツールのみ実行
```
pyfltr ci \
--commands=pyupgrade,autoflake,isort,black,ruff-format,\
ruff-check,pflake8,mypy,pylint,pyright,ty,markdownlint,textlint,pytest \
[files and/or directories ...]
```
カンマ区切りで実行するツールだけ指定する。全サブコマンドで使用可能。
以下のエイリアスも使用可能。(例: `--commands=format`)
- `format`: `pyupgrade` `autoflake` `isort` `black` `ruff-format` `prettier` `uv-sort` `shfmt`
- `lint`:
- Python系: `ruff-check` `pflake8` `mypy` `pylint` `pyright` `ty`
- Markdown系: `markdownlint` `textlint`
- JS/TS系: `eslint` `biome` `oxlint` `tsc`
- その他: `ec` `shellcheck` `typos` `actionlint`
- `test`: `pytest` `vitest`
- `fast`: per-commandの`{cmd}-fast`フラグがtrueのコマンド
※ `pyproject.toml`の`[tool.pyfltr]`で無効になっているコマンドは無視される。
## UI
ターミナル上で実行すると、TextualベースのTUIが自動的に有効になる。
- Summaryタブ: 各コマンドのステータス・エラー数・経過時間をリアルタイム表示
- Errorsタブ: エラー発生時のみ出現し、全コマンドのエラー箇所を`ファイル:行番号`形式で一覧表示
- 各コマンドタブ: コマンドの出力をリアルタイム表示
Errorsタブのエラー一覧は`ファイル:行番号: [コマンド名] メッセージ`形式で、 VSCodeのターミナルからクリックして該当箇所にジャンプできる。
- `--no-ui`: UIを無効化し、出力を直接ターミナルに表示(エラー一覧の後にサマリーを表示)
- `--ci`: CI環境向け(`--no-shuffle --no-ui` 相当)
- `-j N` / `--jobs N`: linters/testersの最大並列数を指定(既定: 4、`pyproject.toml`でも設定可能)
その他のオプションは `pyfltr --help` を参照。
# 設定
# 設定
`pyproject.toml`で設定する。
## 例
```
[tool.pyfltr]
preset = "latest"
pylint-args = ["--jobs=4"]
extend-exclude = ["foo", "bar.py"]
```
## 設定項目
設定項目と既定値は`pyfltr --generate-config`で確認可能。
- preset : プリセット設定(後述)
- python : Python系ツールの一括有効/無効(後述)
- {command} : 各コマンドの有効/無効
- {command}-path : 実行するコマンド
- {command}-args : 追加のコマンドライン引数(lint/fix両モードで常に付与)
- {command}-lint-args : 非fixモード(およびtextlint fix後段のlintチェック) でのみ付与する引数(既定値はtextlintのみ `["--format", "compact"]` を定義)
- {command}-fast : `fast`サブコマンドに含めるか否か(後述)
- {command}-fix-args : `fix`サブコマンド時に`{command}-args`の後に追加する引数(既定値はtextlint / markdownlint / ruff-check / eslint / biomeのみ定義)
- {command}-targets : 対象ファイルパターンの完全上書き(後述)
- {command}-extend-targets : 対象ファイルパターンへの追加(後述)
- {command}-pass-filenames : ファイル引数をコマンドに渡すか否か(既定: `true`。後述)
- {command}-version : bin-runner対応ツールのバージョン指定(既定: `"latest"`。後述)
- prettier-check-args / prettier-write-args : prettierの2段階実行で使う引数(詳細は後述)
- shfmt-check-args / shfmt-write-args : shfmtの2段階実行で使う引数(詳細は後述)
- pylint-pydantic : pylint実行時に`--load-plugins=pylint_pydantic`を自動追加するか(既定: `true`、後述)
- mypy-unused-awaitable : mypy実行時に`--enable-error-code=unused-awaitable`を自動追加するか(既定: `true`、後述)
- jobs : linters/testersの最大並列数(既定値: 4。CLIの`-j`オプションでも指定可能)
- exclude : 除外するファイル名/ディレクトリ名パターン(既定値あり)
- extend-exclude : 追加で除外するファイル名/ディレクトリ名パターン(既定値は空)
- respect-gitignore : `.gitignore`に記載されたファイルを除外するか否か(既定: `true`)。gitのルートおよびネストした`.gitignore`、グローバルgitignore、`.git/info/exclude`を全て考慮する。`git`コマンドが必要
## プリセット設定
`preset`を設定することで、一括して設定を変更できる。 `"latest"` または日付指定 (`"20260411"`, `"20260330"`, `"20250710"`) が使用可能。
```
[tool.pyfltr]
preset = "latest"
```
### preset "20260411" / "latest"
- `pyupgrade = false`
- `autoflake = false`
- `pflake8 = false`
- `isort = false`
- `black = false`
- `ruff-format = true`
- `ruff-check = true`
- `pyright = true`
- `textlint = true`
- `markdownlint = true`
- `actionlint = true`
- `typos = true`
- `uv-sort = true`
### preset "20260330"
- `pyupgrade = false`
- `autoflake = false`
- `pflake8 = false`
- `isort = false`
- `black = false`
- `ruff-format = true`
- `ruff-check = true`
- `pyright = true`
- `textlint = true`
- `markdownlint = true`
### preset "20250710"
- `pyupgrade = false`
- `autoflake = false`
- `pflake8 = false`
- `isort = false`
- `black = false`
- `ruff-format = true`
- `ruff-check = true`
`preset = "latest"`は予告なく動作を変更する可能性がある。
## Python系ツールの一括無効化
`python = false`を設定すると、Python系のツールを一括で無効化する。JS/TS専用プロジェクトで設定を簡潔にする場合に使う。
対象ツール:
- pyupgrade / autoflake / isort / black / ruff-format / ruff-check
- pflake8 / mypy / pylint / pyright / ty / pytest / uv-sort
```
[tool.pyfltr]
python = false
js-runner = "pnpm"
eslint = true
prettier = true
```
以下のツールは`python`設定の影響を受けない。
- npm系ツール: markdownlint / textlint / eslint / prettier / biome / oxlint / tsc / vitest
- bin-runner対応ツール: ec / shellcheck / shfmt / typos / actionlint
適用優先度は `preset < python < 個別設定`。`python = false`でも`mypy = true`のように個別に有効化できる。
## 自動オプション
各ツールの望ましいオプションを自動的にコマンドラインに追加する。`{command}-args`とは独立して動作する。
| 設定 | 既定 | 自動追加される引数 |
| ----------------------- | ------ | -------------------------------------- |
| `pylint-pydantic` | `true` | `--load-plugins=pylint_pydantic` |
| `mypy-unused-awaitable` | `true` | `--enable-error-code=unused-awaitable` |
自動引数は`{command}-args`やCLI引数と重複しないよう排除される。不要な場合は`false`に設定する。
```
[tool.pyfltr]
pylint-pydantic = false
mypy-unused-awaitable = false
```
## ruff-format の 2 段階実行
`ruff-format` は既定で `ruff check --fix --unsafe-fixes` と `ruff format` の2ステップを連続実行する。 importソートや自動修正可能なlint違反を整形と同時に処理するための挙動。
ステップ1のlint違反(ruff checkのexit 1)は無視され、別途 `ruff-check` コマンドで検出される想定。 設定ミス等によるruffの異常終了(exit 2以上)は失敗と判定する。
ステップ1に`--unsafe-fixes`を既定で含めているのは意図的な設計である。`--unsafe-fixes`を外すと自動修正できない違反が増え、手動対処の手間が増加する。実運用ではバージョン管理下で作業するため自動修正は容易に取り消せ、かつ`--unsafe-fixes`が実害のある修正を生むケースはまれである。このため開発体験を優先して既定で有効にしている。保守的に運用したい場合は後述のとおり`ruff-format-check-args`で上書きする。
`pyfltr fix`モード用の`ruff-check-fix-args`(既定値`["--fix", "--unsafe-fixes"]`)も同じ方針で`--unsafe-fixes`を含めている。
```
[tool.pyfltr]
# ステップ 1 をスキップしたい場合 (既定は true)
ruff-format-by-check = false
# ステップ 1 の引数を差し替えたい場合 (既定は ["check", "--fix", "--unsafe-fixes"])
ruff-format-check-args = ["check", "--fix"]
```
## prettier の 2 段階実行
`prettier`は`--check`(読み取り専用)と`--write`(書き込み)が排他のため、pyfltrは2段階で実行する。
- 通常モード: まず`prettier --check`を実行する
- `rc == 0` → `succeeded`(整形済み)
- `rc == 1` → 続けて`prettier --write`を実行し、`rc == 0`なら`formatted`、それ以外は`failed`
- `rc >= 2` → `failed`(設定ミス等の致命的エラー、`--write`は実行しない)
- `--fix`モード: ステップ1(`--check`)をスキップし、直接`prettier --write`を実行する。ファイル内容ハッシュの変化で`formatted` / `succeeded`を判定する
引数は`prettier-check-args` / `prettier-write-args`で個別に上書きできる(既定はそれぞれ`["--check"]` / `["--write"]`)。共通引数`prettier-args`は両ステップの先頭に付与される。
```
[tool.pyfltr]
prettier = true
# キャッシュ等の共通引数
prettier-args = ["--cache"]
```
## shfmtの2段階実行
`shfmt`はprettierと同様に2段階で実行する。
- 通常モード: まず`shfmt -l`(チェックのみ)を実行する
- `rc == 0` → `succeeded`(整形済み)
- `rc != 0` → 続けて`shfmt -w`(書き込み)を実行する
- `--fix`モード: ステップ1(`-l`)をスキップし、直接`shfmt -w`を実行する
引数は`shfmt-check-args` / `shfmt-write-args`で個別に上書きできる(既定はそれぞれ`["-l"]` / `["-w"]`)。共通引数`shfmt-args`は両ステップの先頭に付与される。
```
[tool.pyfltr]
shfmt = true
shfmt-args = ["-i", "2"]
```
## 対象ファイルパターンのカスタマイズ
各コマンドが処理する対象ファイルパターンを変更できる。
`{command}-targets`でパターンを完全に上書きする。
```
[tool.pyfltr]
# shfmtの対象を *.bash のみに変更(既定の *.sh は対象外になる)
shfmt-targets = ["*.bash"]
```
`{command}-extend-targets`で既存パターンに追加する。
```
[tool.pyfltr]
# shfmtの対象に *.sh.tmpl と dot_bashrc を追加(既定の *.sh も維持)
shfmt-extend-targets = ["*.sh.tmpl", "dot_bashrc"]
shellcheck-extend-targets = ["*.sh.tmpl", "dot_bashrc"]
```
両方を指定した場合、`targets`で上書きした後に`extend-targets`で追加する。
## pass-filenames設定
`{command}-pass-filenames = false`を設定すると、コマンド実行時にファイル引数を渡さない。 プロジェクト全体を一括チェックするツール(`tsc`など)で使用する。
ビルトインでは`tsc`が`pass-filenames = false`に設定されている。 カスタムコマンドでも同様に設定可能。
```
[tool.pyfltr]
tsc = true
# tsc は既定で pass-filenames = false のため明示不要
[tool.pyfltr.custom-commands.commitlint]
type = "linter"
path = "commitlint"
args = ["--from=HEAD~1"]
pass-filenames = false
```
## ネイティブバイナリツール (bin-runner)
ec / shellcheck / shfmt / typos / actionlintはネイティブバイナリ(Go/Rust/Haskell製等)で、`bin-runner`設定で起動方式を切り替える。 ecはeditorconfig-checkerの略称。既定は`mise`で、[mise](https://mise.jdx.dev/)によるバージョン管理付きの実行となる。
```
[tool.pyfltr]
# mise経由で実行する(既定)
bin-runner = "mise"
```
| `bin-runner` | 挙動 |
| ------------ | --------------------------------------------------------------------------------------------- |
| `mise` | `mise exec @ -- `で起動する(既定)。ツールの自動インストールにも対応 |
| `direct` | PATH上のバイナリを直接実行する |
ツールが見つからない場合はエラー扱い(`failed`)となる。 `mise`モードの場合、実行環境にmiseがインストールされている必要がある。
### CIでの設定
GitHub ActionsでCIを実行する場合は[jdx/mise-action](https://github.com/jdx/mise-action)でmiseをセットアップする。
```
- name: Setup mise
uses: jdx/mise-action@v4
```
miseを使わず、PATH上のバイナリを直接使う場合は`bin-runner = "direct"`を設定する。
### バージョン指定
`{command}-version`でbin-runner対応ツールのバージョンを指定できる。既定は`"latest"`。
```
[tool.pyfltr]
shellcheck-version = "0.10.0"
shfmt-version = "3.10.0"
```
miseモードでは`mise exec @ -- `として展開される。directモードではバージョン指定は無視される。
### bin-runner対応ツールの設定
各ツールはすべて既定で無効。有効化には`pyproject.toml`で切り替える。
```
[tool.pyfltr]
ec = true
shellcheck = true
shfmt = true
typos = true
actionlint = true
```
既定の引数は以下のとおり。必要に応じて上書きできる。
- ec: `ec-args = ["-format", "gcc", "-no-color"]`
- shellcheck: `shellcheck-args = ["-f", "gcc"]`
- shfmt: `shfmt-check-args = ["-l"]` / `shfmt-write-args = ["-w"]`(2段階実行。共通引数は`shfmt-args`で指定)
- typos: `typos-args = ["--format", "brief"]`
- actionlint: `actionlint-args = []`
`{command}-path`を明示的に設定した場合はその値が優先され、bin-runnerによる自動解決は無効化される。
## JS/TS追加ツール (oxlint / tsc / vitest)
oxlint / tsc / vitestはjs-runner対応のツール。すべて既定で無効。
```
[tool.pyfltr]
js-runner = "pnpm"
oxlint = true
tsc = true
vitest = true
```
既定の引数は以下のとおり。
- oxlint: `oxlint-args = []`
- tsc: `tsc-args = ["--noEmit"]`、`tsc-pass-filenames = false`(プロジェクト全体をチェックするためファイル引数を渡さない)
- vitest: `vitest-args = ["run"]`(`run`サブコマンドが必須)
## uv-sort
`uv-sort`は`pyproject.toml`の依存定義をソートするformatter。既定で無効。
```
[tool.pyfltr]
uv-sort = true
```
Python系ツールとして扱われ、`python = false`で一括無効化の対象となる。
## 並列実行
linters/testersは既定で最大4並列で実行される。 `jobs`で変更可能。
```
[tool.pyfltr]
jobs = 8
```
CLIオプション`-j`でも指定でき、`pyproject.toml`より優先される。
実行順は`fast`フラグに基づいて最適化され、`fast = false`のツール(mypy、pylint、pytest等)が先に開始される。
## fastエイリアス
`fast`サブコマンドで実行されるコマンドは、各コマンドの`{command}-fast`設定で制御される。
```
[tool.pyfltr]
# mypyをfastに追加
mypy-fast = true
# pflake8をfastから除外
pflake8-fast = false
```
カスタムコマンドも`fast = true`でfastエイリアスに追加できる(後述)。
## npm系ツール (markdownlint / textlint / eslint / prettier / biome / oxlint / tsc / vitest)
markdownlint-cli2・textlint・eslint・prettier・biome・oxlint・tsc・vitestは`js-runner`設定で起動方式を切り替える。 既定は`pnpx`で、グローバル/キャッシュから都度取得する従来互換の挙動となる。 プロジェクトの`package.json`で既にこれらのツールをインストール済みの場合は、 `js-runner`を`pnpm` / `npm` / `npx` / `yarn` / `direct`に切り替えるとよい。 これによりCIなどでの再ダウンロードを避けられる。 eslint / prettier / biomeはプラグイン(`typescript-eslint`・`prettier-plugin-svelte`等)を`package.json`で管理するのが一般的。 これらのツールを使うプロジェクトでは`js-runner = "pnpm"`(もしくは`npm` / `yarn` / `direct`)を推奨する。
```
[tool.pyfltr]
# プロジェクトの node_modules を使う (pnpm exec 経由)
js-runner = "pnpm"
```
| `js-runner` | 挙動 |
| ----------- | ------------------------------------------------------------------------- |
| `pnpx` | `pnpx`経由で起動する (既定)。`textlint-packages`は`--package`で展開される |
| `pnpm` | `pnpm exec`経由で起動する。パッケージは`package.json`側で管理する |
| `npm` | `npm exec --no --`経由で起動する |
| `npx` | `npx --no-install`経由で起動する。`textlint-packages`は`-p`で展開される |
| `yarn` | `yarn run`経由で起動する |
| `direct` | `node_modules/.bin/`配下の実行ファイルを直接起動する |
`{command}-path`を明示的に設定した場合はその値が優先され、自動解決は無効化される。グローバルインストール済みのtextlintを直接使いたい場合などに利用する。
```
[tool.pyfltr]
textlint-path = "textlint"
# 共通引数 (lint/fix 両モードで付与)
textlint-args = []
# lint モード専用の引数 (既定で --format compact。builtin パーサが compact 出力を想定している)
textlint-lint-args = ["--format", "compact"]
```
textlintのfix実行 (`textlint --fix`) では `@textlint/fixer-formatter` が使われ、`compact` フォーマッタを解決できない。このため `--format compact` は `textlint-args`(共通)ではなく `textlint-lint-args`(lintモード専用)に分離している。
`pyfltr fix` 実行時、pyfltrはtextlintを2段階で実行する(fix適用 → lintチェック)ため、 残存違反はcompact形式で正しく取得される。 旧版から `textlint-args = ["--format", "compact", ...]` の設定を引き継いでいる場合でも、 pyfltrはfixステップの起動コマンドから `--format` ペアを自動除去するためクラッシュしない。 新規設定では `textlint-lint-args` に書くことを推奨する。
### textlintのプリセット/ルール指定
textlintで利用するルール/プリセットパッケージは`textlint-packages`に列挙する。既定では以下の3パッケージが含まれる。
```
[tool.pyfltr]
textlint-packages = [
"textlint-rule-preset-ja-technical-writing",
"textlint-rule-preset-jtf-style",
"textlint-rule-ja-no-abusage",
]
```
`textlint-packages`は`pnpx` / `npx`モード時に`--package` / `-p`展開される。`pnpm` / `npm` / `yarn` / `direct`モードでは`package.json`側でインストールする前提のため無視される。
### eslint / prettier / biomeの設定
eslint / prettier / biomeはすべて既定で無効。 有効化には`pyproject.toml`で切り替える。 プラグインは`package.json`管理が前提のため、通常は`js-runner = "pnpm"`と併用する。
```
[tool.pyfltr]
js-runner = "pnpm"
eslint = true
prettier = true
biome = true
```
既定の引数は以下のとおり。 必要に応じて上書きできる。
- eslint:
- `eslint-args = ["--format", "json"]`(lint / fix両モードで有効にするため共通argsに配置)
- `eslint-fix-args = ["--fix"]`
- 注: ESLint 9系以降で`compact` / `unix` / `tap`等のコアフォーマッタは除去されたため、コア標準の`json`を採用している
- `eslint-args`を上書きする際は非コアフォーマッタを使わないこと
- prettier:
- `prettier-check-args = ["--check"]` / `prettier-write-args = ["--write"]`
- 2段階実行の詳細は「prettierの2段階実行」を参照
- biome:
- `biome-args = ["check", "--reporter=github"]`(`check`サブコマンドと機械可読出力を共通argsで常時適用)
- `biome-fix-args = ["--write"]`(safe fixのみ。unsafe fixを使う場合は`["--write", "--unsafe"]`に上書き)
- 注: `biome-args`の先頭からサブコマンド(`check` / `lint` / `format`)を外すとbiomeがhelp表示で失敗する。必ずサブコマンド名を残すこと
プリセット(`preset = "latest"`)にはeslint / prettier / biome / oxlint / tsc / vitestは含まれない(opt-in)。
## 出力順序
非TUIモード (`--no-ui`、`--ci`、または非対話端末) では、既定で全コマンドの完了後に成功コマンド詳細 → 失敗コマンド詳細 → `summary`の順でまとめて出力する。`pyfltr ... | tail -N`のようにパイプで末尾だけ切り出してもsummaryと失敗情報が末尾に残るため、Claude Codeなど末尾だけを読み取るツールでも実行結果を把握できる。
従来の「各コマンドの完了時に即座に詳細ログを出す」挙動を使いたい場合は`--stream`を指定する。
## カスタムコマンド
`[tool.pyfltr.custom-commands]`で任意のツールを追加できる。
```
[tool.pyfltr.custom-commands.bandit]
type = "linter"
path = "bandit"
args = ["-r", "-f", "custom"]
targets = "*.py"
error-pattern = '(?P[^:]+):(?P\d+):(?P\d+):\s*(?P.+)'
fast = true
```
設定項目。
- `type`(必須): `"formatter"` / `"linter"` / `"tester"`
- formatterは直列実行、linter/testerは並列実行
- `path`: 実行コマンド(省略時はコマンド名)
- `args`: 追加引数(省略時は空)
- `targets`: 対象ファイルパターン(省略時は`"*.py"`)
- `error-pattern`: エラーパース用正規表現(省略可)
- `file`と`line`と`message`の名前付きグループが必須
- `col`は任意
- 指定するとErrorsタブやエラー一覧に表示される
- `fast`: `fast`サブコマンドに含めるか否か(省略時は`false`)
- `fix-args`: `pyfltr fix`時に`args`の後ろへ追加する引数(省略時はfixモード対象外)
- `pass-filenames`: ファイル引数をコマンドに渡すか否か(省略時は`true`)。プロジェクト全体を一括チェックするツールでは`false`に設定する
ビルトインコマンド(mypy等)は自動的にエラーパースされる。 カスタムコマンドに対しても`--{name}-args`やenable/disableを使用できる。
### カスタムコマンドでの fix モード対応
autofix機能を持つツールをカスタムコマンドとして登録する場合は、`fix-args`を定義しておくと`pyfltr fix`の対象に含まれる。
```
[tool.pyfltr.custom-commands.my-linter]
type = "linter"
path = "my-linter"
args = ["--check"]
fix-args = ["--fix"]
```
fixモードでは`args`の後に`fix-args`が追加され、`my-linter --check --fix `として実行される。
# 設定例
## pyproject.toml
pyfltr本体の設定(`[tool.pyfltr]`)と、呼び出される各ツール(ruff / mypy / pytest)の設定を1つの`pyproject.toml`にまとめた例。
- `preset = "latest"`: 主要ツールを有効化するプリセット(現在は`20260411`相当)。ruff-format / ruff-check / pyrightなど8ツールが有効化され、旧ツール(pyupgrade / autoflake / isort / black / pflake8)は無効化される。詳細は[docs/configuration.md](https://ak110.github.io/pyfltr/guide/configuration/index.md)の「プリセット設定」を参照。
- `pylint-args`: pylintに追加で渡す引数。`--load-plugins=pylint_pydantic`と`--enable-error-code=unused-awaitable`(mypy)は自動オプションで既定有効のため個別指定不要。
- ruffの `per-file-ignores`: テストコード(`**_test.py`)とpackage init(`__init__.py`)のdocstring要求を除外する実用的な調整。
```
[dependency-groups]
dev = [
...
"pyfltr",
]
...
[tool.pyfltr]
preset = "latest"
pylint-args = ["--jobs=4"]
[tool.ruff]
# https://docs.astral.sh/ruff/configuration/
line-length = 128
[tool.ruff.lint]
# https://docs.astral.sh/ruff/linter/#rule-selection
select = [
# pydocstyle
"D",
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# flake8-import-conventions
"ICN",
# isort
"I",
]
ignore = [
"D107", # Missing docstring in `__init__`
"D415", # First line should end with a period
]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.lint.per-file-ignores]
"**_test.py" = ["D"]
"**/__init__.py" = ["D104"] # Missing docstring in public package
[tool.mypy]
# https://mypy.readthedocs.io/en/stable/config_file.html
allow_redefinition = true
check_untyped_defs = true
ignore_missing_imports = true
strict_optional = true
strict_equality = true
warn_no_return = true
warn_redundant_casts = true
warn_unused_configs = true
show_error_codes = true
[tool.pytest.ini_options]
# https://docs.pytest.org/en/latest/reference/reference.html#ini-options-ref
addopts = "--showlocals -p no:cacheprovider --maxfail=5 --durations=30 --durations-min=0.5"
log_level = "DEBUG"
xfail_strict = true
asyncio_mode = "strict"
asyncio_default_fixture_loop_scope = "session"
asyncio_default_test_loop_scope = "session"
```
### JS/TSを併用するプロジェクトでの推奨設定
JS/TSを併用するプロジェクトでは、`js-runner`をプロジェクトのパッケージマネージャーに合わせることを推奨する。 既定の`pnpx`はツールを都度取得するため、CIで毎回ダウンロードが発生する。 `pnpm`や`npm`など、プロジェクトで使用しているパッケージマネージャーを指定すれば、`package.json`で管理済みのパッケージを再利用できる。
```
[tool.pyfltr]
js-runner = "pnpm"
```
`pnpm` / `npm` / `yarn` / `direct`では`textlint-packages`は無視される(`package.json`側でインストールする前提のため)。 textlintのプリセットやルールも`package.json`の`devDependencies`で管理すること。
詳細は[docs/configuration.md](https://ak110.github.io/pyfltr/guide/configuration/index.md)の「npm系ツール」を参照。
### JS/TS専用プロジェクトでの推奨設定
JS/TS専用プロジェクトでは、`python = false`でPython系ツールを一括無効化し、必要なJS/TSツールを個別に有効化する。
```
[tool.pyfltr]
python = false
js-runner = "pnpm"
eslint = true
prettier = true
markdownlint = true
textlint = true
vitest = true
```
pre-commitの設定例。JS/TS専用プロジェクトではpyfltrをdev依存に含めないため、`uvx`で都度取得する。
```
- repo: local
hooks:
- id: pyfltr
name: pyfltr
entry: uvx pyfltr fast
types_or: [javascript, jsx, ts, tsx, json, css, yaml, markdown]
require_serial: true
language: system
```
ポイント:
- `python = false`: Python系ツールを一括無効化する。対象ツールの一覧は[docs/configuration.md](https://ak110.github.io/pyfltr/guide/configuration/index.md)の「Python系ツールの一括無効化」を参照。
- `uvx pyfltr fast`: pyfltrをdev依存に含めないJS/TS専用プロジェクトでは、`uvx`で都度取得して実行する。
- `types_or`: プロジェクトで使用するファイルタイプを列挙する。Pythonは不要なため含めない。
## .pre-commit-config.yaml
```
- repo: local
hooks:
- id: pyfltr
name: pyfltr
entry: uv run --frozen pyfltr fast
types_or: [python, markdown, toml]
require_serial: true
language: system
```
ポイント:
- `--frozen`: `uv run`が依存解決を再実行せず`uv.lock`をそのまま使うようにする。サプライチェーン攻撃対策として、`git commit`の起動経路がシェル環境変数(`UV_FROZEN`)に依存しなくても確実にfrozen動作させるための保険。
- `fast`: mypy / pylint / pytestなど重いコマンドを除外した高速サブセット。Formatterがファイルを修正しただけではフックを失敗と判定しない。pre-commitは対話的フックのため速度を優先する。
- `types_or: [python, markdown, toml]`: PythonだけでなくMarkdown変更時にmarkdownlint / textlintを、TOML変更時にuv-sortを実行する。
- `require_serial: true`: pyfltr自身が内部で並列化するため、pre-commit側での多重起動を避ける。
## .markdownlint-cli2.yaml
markdownlint-cli2が読み込む設定ファイル。`$schema` を指定してエディタ補完を有効化する。 日本語ドキュメントでは行長制限が実用的でないため、`line-length` チェックのみ無効化している。
```
$schema: https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/v0.20.0/schema/markdownlint-cli2-config-schema.json
config:
line-length: false
```
## .textlintrc.yaml
textlintで技術文書向けの複数プリセットと誤用語チェックを併用する例。 `preset-ja-technical-writing` / `preset-jtf-style` / `ja-no-abusage` を組み合わせる。 原則はデフォルトルールに従い、誤検出や技術文書に合わないルールのみ個別に無効化する。
無効化しているルールと理由は以下の通り。
- `ja-no-mixed-period`: ラベル型見出し(「ポイント」「例」など)が多用されるため
- `no-doubled-joshi`: 技術文書で避けられない自然な助詞連結が頻出するため
- `sentence-length`: 既定の100文字制限を120文字へ緩和する(完全無効化はしない)
- `no-mix-dearu-desumasu`: 本文・リストを常体(である調)に固定する(プリセット既定は本文が敬体)
- `1.1.3.箇条書き`: 箇条書きに句点を付けない方針のため
- `4.2.7.コロン(:)`: コロン終端のラベル記法を多用するため
対応する`textlint-packages`の設定例は[textlint-packagesのカスタマイズ](#textlint-packages%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA)を参照。
```
rules:
preset-ja-technical-writing:
# ラベル型見出し ("ポイント:", "例:" など) が多用されるため、文末句点の強制を無効化する
ja-no-mixed-period: false
# 技術文書における自然な助詞連結 (「〜かどうかを検討するか」など) が頻出するため無効化する
no-doubled-joshi: false
# 引用文や詳細な技術説明で100文字超過が避けられないため緩和する
sentence-length:
max: 120
# ドキュメントを常体(である調)で統一する方針のため
no-mix-dearu-desumasu:
preferInHeader: ""
preferInBody: "である"
preferInList: "である"
strict: false
preset-jtf-style:
"1.1.3.箇条書き":
shouldUsePoint: false # 箇条書きは「。」をつけない
# コロン終端のラベル記法を多用するため無効化する
"4.2.7.コロン(:)": false
ja-no-abusage: true
```
## textlint-packagesのカスタマイズ
追加のtextlintプリセットを使う場合は `textlint-packages` にパッケージ名を列挙する(pnpx / npx起動時に `--package` / `-p` として展開される)。
```
[tool.pyfltr]
textlint-packages = [
"textlint-rule-preset-ja-technical-writing",
"textlint-rule-preset-jtf-style",
"textlint-rule-ja-no-abusage",
]
```
共通のコマンドライン引数を追加したい場合は `textlint-args` を使う。 lint専用のオプション(`--format compact` など)は `textlint-lint-args` に分離する。
```
[tool.pyfltr]
textlint-args = []
textlint-lint-args = ["--format", "compact"]
```
旧版の`textlint-args = ["--format", "compact", ...]`をそのまま引き継いでもクラッシュしない。 pyfltrは`pyfltr fix`実行時にfix段階の起動コマンドから`--format`ペアを自動除去するため。 ただし新規設定では`textlint-lint-args`に書くことを推奨する。
## CI
GitHub ActionsでpyfltrをPythonバージョンのmatrixで実行する構成の例。
```
env:
# 開発モード: DeprecationWarningなどの隠れた問題を早期検出する
PYTHONDEVMODE: "1"
# サプライチェーン攻撃対策: uvがlockfileを常に尊重する
UV_FROZEN: "1"
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v8
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "lts/*"
- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: latest
- name: Configure pnpm security
run: pnpm config set minimum-release-age 1440 --global
- name: Install dependencies
run: uv sync --all-extras --all-groups
- name: Test with pyfltr
run: uv run pyfltr ci
- name: Prune uv cache for CI
run: uv cache prune --ci
```
ポイント:
- `env.PYTHONDEVMODE: "1"`: Pythonの開発モードを有効化する。`DeprecationWarning`の表示や各種デバッグチェックが有効になり、隠れた問題を早期に検出できる。
- `env.UV_FROZEN: "1"`: サプライチェーン攻撃対策として、ワークフロー全体で`uv sync`/`uv run`が`uv.lock`を尊重するよう強制する。意図しない再resolveでロックファイルが書き換わるリスクを抑える。
- `actions/setup-node` + `pnpm/action-setup`: `markdownlint-cli2`と`textlint`をpnpx経由で呼び出すため、PythonだけでなくNode.js環境も必要になる。
- `pnpm config set minimum-release-age 1440`: サプライチェーン攻撃対策として、公開から24時間(1440分)未満のパッケージのインストールを拒否する。
- `uv sync --all-extras --all-groups`: pyfltrを含むdev依存をすべて同期し、`uv run pyfltr`から対応ツール群を解決できるようにする。`UV_FROZEN=1`下でも`uv.lock`をそのまま使うため問題なく動作する。
- `uv cache prune --ci`: CIキャッシュを軽量化するための後処理。
# カスタムコマンド例
`[tool.pyfltr.custom-commands]`で任意のツールを追加できる。 ここでは実用的な設定例を紹介する。 カスタムコマンドの仕様は[設定](https://ak110.github.io/pyfltr/guide/configuration/index.md)の「カスタムコマンド」セクションを参照。
## Pythonセキュリティ・品質ツール
### bandit(セキュリティチェック)
```
[tool.pyfltr.custom-commands.bandit]
type = "linter"
path = "bandit"
args = ["-r", "-f", "custom"]
targets = "*.py"
error-pattern = '(?P[^:]+):(?P\d+):(?P\d+):\s*(?P.+)'
fast = true
```
### deptry(未使用・不足依存の検出)
```
[tool.pyfltr.custom-commands.deptry]
type = "linter"
path = "deptry"
args = ["."]
targets = "*.py"
pass-filenames = false
```
### vulture(未使用コードの検出)
```
[tool.pyfltr.custom-commands.vulture]
type = "linter"
path = "vulture"
args = []
targets = "*.py"
error-pattern = '(?P[^:]+):(?P\d+):\s*(?P.+)'
fast = true
```
### detect-secrets(シークレット検出)
```
[tool.pyfltr.custom-commands.detect-secrets]
type = "linter"
path = "detect-secrets"
args = ["scan", "--list-all-plugins"]
targets = "*.py"
pass-filenames = false
```
## 汎用ツール
### yamllint(YAML構文チェック)
```
[tool.pyfltr.custom-commands.yamllint]
type = "linter"
path = "yamllint"
args = ["--format", "parsable"]
targets = ["*.yaml", "*.yml"]
error-pattern = '(?P[^:]+):(?P\d+):(?P\d+):\s*\[(?:error|warning)\]\s*(?P.+)'
fast = true
```
### codespell(スペルチェック)
```
[tool.pyfltr.custom-commands.codespell]
type = "linter"
path = "codespell"
args = []
targets = ["*.py", "*.md", "*.rst", "*.txt"]
fast = true
```
### cspell(スペルチェック、npm系)
js-runner対応のスペルチェッカー。`package.json`でインストールする前提で、`js-runner = "pnpm"`と併用する。
```
[tool.pyfltr]
js-runner = "pnpm"
[tool.pyfltr.custom-commands.cspell]
type = "linter"
path = "cspell"
args = ["lint", "--no-progress", "--no-summary"]
targets = ["*.py", "*.md", "*.ts", "*.js"]
error-pattern = '(?P[^:]+):(?P\d+):(?P\d+)\s*-\s*(?P.+)'
fast = true
```
## JS/TSプロジェクト向け
### svelte-check(Svelteの型チェック)
```
[tool.pyfltr.custom-commands.svelte-check]
type = "linter"
path = "svelte-check"
args = ["--tsconfig", "./tsconfig.json"]
targets = "*.svelte"
pass-filenames = false
```
### commitlint(コミットメッセージチェック)
```
[tool.pyfltr.custom-commands.commitlint]
type = "linter"
path = "commitlint"
args = ["--from=HEAD~1"]
pass-filenames = false
```
# 開発者向け
# 開発手順
## 開発環境の構築手順
1. 本リポジトリをcloneする
1. [uvをインストール](https://docs.astral.sh/uv/getting-started/installation/)する
1. [pre-commit](https://pre-commit.com/)フックをインストールする
```
uv run pre-commit install
```
1. サプライチェーン攻撃対策として`uvx`/`pnpx`用のグローバル設定をする
```
mkdir -p ~/.config/uv && echo 'exclude-newer = "1 day"' >> ~/.config/uv/uv.toml
pnpm config set minimum-release-age 1440 --global
```
## UV_FROZENによるlockfile尊重(サプライチェーン攻撃対策)
CI/`make`などの自動実行環境で`uv sync`/`uv run`が依存解決を再実行せず`uv.lock`をそのまま使うよう、環境変数`UV_FROZEN=1`を常時有効化している。 意図しない再resolveでロックファイルが書き換わるリスクを抑え、`pyproject.toml`の`exclude-newer = "1 day"`と組み合わせて二重防御として機能する。
- `make format`や`make test`は`Makefile`の`export UV_FROZEN := 1`で自動適用される
- CIは`.github/workflows/*.yaml`の`env.UV_FROZEN`で自動適用される
- `git commit`経由のpre-commitフックは`.pre-commit-config.yaml`のlocal hookのentryに`--frozen`を明示している
開発者のシェルでは`UV_FROZEN`を設定しない前提なので、依存の追加・更新は通常どおり`uv add`/`uv remove`/`uv lock --upgrade-package`を使えばよい。 `make update`も内部で自動的にUV_FROZENを外すため、そのまま実行してよい。
## READMEとdocsの役割分担
本プロジェクトのドキュメントは以下の構成で配置している。
- README.md: 概要・特徴・インストール手順・ドキュメントへのリンクを網羅する「玄関」。README.mdだけを読めばプロジェクトの目的と使い始めるための入口が把握できる状態を保つ
- docs/guide/: 利用者向けの詳細情報(対応ツール一覧・設定リファレンス・使い方など)
- docs/development/: 開発者向けの情報(セットアップ・リリース手順など)
README.mdとdocs側(とくに`docs/index.md`)で概要・特徴・インストール手順が部分的に重複する場合がある。README.mdはGitHubトップとして、docs側は公開ドキュメントサイトの入口としてそれぞれ自己完結する必要があるため、この重複は許容する。
変更頻度が低いため二重管理のコストより一貫性・可読性のメリットが上回ると判断した。変更時は、docs側で同じ情報を再掲している箇所があれば同じコミット内で合わせて更新する。
## ドキュメント
ドキュメントはMkDocsで管理し、GitHub Pagesでホスティングしている。
### ローカルプレビュー
```
uv run mkdocs serve
```
でプレビューを確認できる。
### GitHub Pagesの設定
初回のみリポジトリの設定が必要。
1. GitHubのリポジトリ設定ページを開く
1. `Settings` → `Pages` に移動する
1. Sourceを「GitHub Actions」に設定する
masterブランチへのpush時にdocs/配下やmkdocs.ymlの変更があると自動デプロイされる。
## リリース手順
事前に`gh`コマンドをインストールして`gh auth login`でログインしておき、以下のコマンドのいずれかを実行。
```
gh workflow run release.yaml --field="bump=バグフィックス"
gh workflow run release.yaml --field="bump=マイナーバージョンアップ"
gh workflow run release.yaml --field="bump=メジャーバージョンアップ"
```
で状況を確認できる。
## コミットメッセージ (Conventional Commits)
Conventional Commits形式に従う。ただし記述の方向性があまり変わらないような軽微な修正は`chore`などにしてよい。