ハイパーモダンPython 雑読書感想

この記事はオライリー・ジャパンより刊行された「[ハイパーモダンPython](https://www.oreilly.co.jp/books/9784814400928/)」の感想記事です。

# 1章 Pythonのインストール
各OSでPythonをインストールしたときのPathの解決方法やバージョンの管理方法を解説した章。
私はWindows使いだが概ね知っている内容であった(`py -3.11` のようにPythonのバージョンを指定できることなど)。

## 1.3 WindowsにPythonをインストールする
> **Microsoft Store の Python**
> Windowsには、Microsoft Storeにある最新のPythonパッケージ（略）
> 初心者にPythonを教えるには便利ですが、中級者や上級者が使うにはお勧めできません。

直感でStoreから入手できるPythonを使わないほうがよいことを知っていたが、具体的にその理由を知ることができた。
次からは自信をもって周りに非推奨と言える。

## 1.10 挑戦的な新しい世界：HatchとRye
HatchとRyeについて解説があった。本書が執筆された時点では情報が充実しておらず内容は軽く触れられている程度だが、
Poetry などをすっとばして venv → Hatch と Rye に移行した私からすると歴史を含めた外観が掴めてよかった。

# 2章 Python環境
仮想環境などを解説した

## 2.2 pipx について
私は `pipx` コマンドを知らずユーティリティであっても毎回新規仮想環境に追加していたので知っていたら便利そうだと思った (rye に移行して最近は使う機会がなさそう……)。

# 2.3 uv について
最近使ってる。速くていいね！


# 3章 Pythonパッケージ
Python プロジェクトの管理やpyproject.tomlなどの説明とパッケージ化するための方法

知識としてはふんわり知っていたことが明文化されて腑に落ちた部分が色々あった。

## 3.8 プロジェクトレイアウト
なぜ src レイアウトを取るか？ということについて。

```
package-name
├─ pyproject.toml
└─ src
    └─ package_name
        ├─ __init__.py
        └─ app.py
```

+ なぜモダンなプロジェクトでは src ディレクトリ下にファイルをプロジェクトを入れるのか？
+ package_name フォルダを直下に作成することではダメなのか？

今までうっすら知っていたが、具体例を示して上のレイアウトを推奨する理由が解説されており助かった。

## 3.9 Rye によるパッケージ管理
Ryeの解説があって助かる。

## 3.10 wheel と dist
自前のプロジェクトでは基本コードを直接配布しており (`pip git+...`) build 周りをよく知らなかったので勉強になった。

## 3.11.10 ライセンス
pyproject.toml 内の project.license フィールドについて。
私が業務で参加するプロジェクトは一般に公開されることがないがその際は

```toml
[project]
license = { text = "proprietary" }
classifiers = [
    "License :: Other/Proprietary License",
    "Private :: Do Not Upload",
]
```

とするとよいらしい。もちろん PyPI に登録することはないが、
万が一アップロードしようとしてもこの表記があると PyPI 側に登録されることがない。
> To prevent a package from being uploaded to PyPI, use the special "Private :: Do Not Upload" classifier. PyPI will always reject packages with classifiers beginning with "Private ::".
> https://pypi.org/classifiers/

## 3.11.11 要求されるPythonのバージョン
project.requires-python で上限が指定されてはならない。→ ふんわりとした理解を明文化してくれた。

# 4章 依存関係の管理
ライブラリの依存関係などについて

## 4.2.1 バージョン指定子
> **Pythonのバージョン上限**
> バージョン上限は解決不可能な依存関係の衝突の原因となります。（略）
> 依存関係に上限があると、下流プロジェクトがセキュリティやバグの修正が受けられなくなっていまします。

Pythonのパッケージ依存関係において上限をしていしてはならない。知っていたが改めて重要性を認識。

### 4.2.2.1 オプショナルな依存関係
project.optional-dependencies について

エクストラパッケージについてとその際の実装について、本文中で次のように紹介されていた。
```py
try:
    import h2
except ImportError:
    h2 = None

# 事前にh2をインポートできているか確認
if h2 is not None:
    ...
```

私のプロジェクトでは下のような書き方をしていたが、上のほうがグローバル変数をなくすことができスマートかもしれない？
```py
EXIST_H2_LIB = True
try:
    import h2
except ImportError:
    EXIST_H2_LIB = False

if EXIST_H2_LIB:
    ...
```

## 4.2.3 環境マーカー
こちらも私のプロジェクトではPython 3.9 以前のコードに対応するため `typing_extension` モジュールのインストールを依存関係に追加しているが、すべてのバージョンで必要ではないので制限を加えてもよいと感じた。

書籍内のコード（一部略）
```toml
dependencies = [
    "importlib-metadata>=6.7.0; python_version < '3.8'",
]
```
```py
if sys.version_info >= (3, 8):
    from importlib.metadata import metadata
else:
    from importlib_metadata import metadata
```

私のコード
```toml
dpendencies = [
    "typing-extensions",
]
```
```py
try:
    from typing import Literal
except ImportError:
    from typing_extensions import Literal
```

書籍の例はどのPythonバージョン向けに書かれたのかコードから明確わかり、可読性が高いと感じた。


## 4.3.2 オプショナルな依存関
**再帰的オプション依存関係**として下の例が紹介されていた。
```toml
[project.optional-dependencies]
tests = ["pytest>7.4.4", "pytest-sugar>1.0.0"]
docs = ["sphinx>5.3.0"]
dev = ["random-wikipedia-article[tests,docs]"]
```

オプショナルから別のオプショナル依存を呼び出せるらしい。今までは dev にすべてのパッケージを再羅列していたのでこちらを活用したい。(rye もできたらいいな)

rye で検討中らしい？
 + https://github.com/astral-sh/rye/issues/818
 + https://github.com/astral-sh/rye/issues/825
 + https://github.com/astral-sh/rye/issues/1138
 + https://github.com/astral-sh/rye/issues/705

## 4.4 依存関係をロックする
ロックファイルについて

こちらも利用しているがふんわりしているので明文化されて助かった。（でも複数バージョンでロックファイルはどうやって作るんだろう→後の方に uv の例が載っていた）

なぜ依存関係のロックを toml 内に記述すべきでないか書かれていた。

# 5章 Poetryによるプロジェクト管理
Poetry の紹介と設定について。

Rye は次世代 Poetry という雰囲気があるので、熟読はしなかったが歴史をたどるうえで読む価値はあった。

## 5.2 プロジェクトの作成
src-tests レイアウトとそれが採用される理由について改めて記してあった。

# 6章 pytestによるテスト
pytest とツールの設定や拡張について

## 6.6.2 pytest-xdist
pytest のプラグイン xdist はテストをランダムなCPUプロセスに割り当てて実行する。

> テスト順序のランダム化は、テスト間の依存関係を検出するのにも便利です[^6]。
> [^6] 訳注：テスト順序をランダム化する場合はpytest-randomlyプラグインを採用するとよい。

テストのランダム化は採用すべきと感じた。

## 6.6.4 その他プラグイン
いくつかプラグインが列挙してあった。その中に気になるプラグインがあったので採用を検討したい。

+ pytest-sugar: プログレスバーを表示する
+ typeguard: 実行時に型チェックを行う


## 6.7 まとめ
> pytestを使ったテストについて詳しく知りたい方は、Brainの本を読んでみてください。
[テスト駆動Python 第2版](https://www.shoeisha.co.jp/book/detail/9784798177458)

とりあえずより詳しい解説を読みたいと思ったので買う。

# 7章 Coverage.pyによるカバレッジ測定
コードカバレッジの計測について。
プロジェクトでもカバレッジの測定を行っているが一部新たな発見があった。

## 7.1 Coverage.py を使う

> カバレッジが100%を下回った際にCoverage.pyが失敗するように設定しましょう。
>
> [tool.coverage.report]
> fail_under = 100

カバレッジレポートの何パーセンをクリアを目標とするか決めかねているので（最近導入したばかり）本書では100%を推奨としているようだ。
`fail_under` オプションは初めて知った（カバレッジを把握するために出力をこねこねする必要がなかったんだ！？）

## 7.3 複数の環境におけるテスト
## 7.4 並列カバレッジ

> if sys.version_info >= (3, 8):
> （略）
> Python 3.7でCoverage.pyを再び実行すると、（略）if文の最初の分岐が欠落することがわかります。
> （略）
> このような文をカバレッジ測定の対象から外したいと考えるかもしれませんが、外すべきではありません。

今までignoreしてきたので図星だった。今後対応したい。

## 7.6 カバレッジが目指すもの
> 新規プロジェクトにおいては、カバレッジ100%以外に意味のある目標はありません。
> （略）
> レガシーなプロジェクトでは最方言のテストカバレッジしかないことも多いでしょう。一般的なルールとして、そのようなプロジェクトでのカバレッジは**単調増加**していくべきです。

明確な目標が示されていた。

# 8章 Nox による自動化
Noxによるプロジェクト保守タスクの自動化について。

以前 tox を利用しようとして挫折したのでこちら勉強したい。(CI で十分かな？)

もっと読み込む必要があるので感想はスキップ

# 9章 Ruffとpre-commitによるリント
リンター/フォーマッターであるRuffの紹介とpre-commitでそれを強制する技術について

Ruffについてはすでに導入しているので知っている技術がほとんどだった。

## 9.3 pre-commitフレームワーク
pre-commit についても検証することがいろいろあるので後ほど別で勉強が必要そうだ……。

# 10章 安全性とインスペクションのための型アノテーション
静的型チェックとそのためのツール (mypy など) の紹介

私のプロジェクトではすでに導入しているので軽く読んだ。

## 10.3.3 Strictモード
> 新規のPythonプロジェクトでは、最初からStrictモードを有効にすることを進めます。

私のプロジェクトも見直す必要がありそうだ（いくつかのオプションを設定しているがStrictモードのすべての制限が有効になっていない）。

> 筆者が気に入っているmypyの設定はprettyフラグです。prettyを有効にすると、エラーが発生した箇所のスニペットや行数などが表示されます。

この設定は知らなかったので試したい。

## 10.3.6 テストに対する型チェック
> テストコードを他のコードと同じように扱ってください。テストコードに対しても型チェックをすれば、pytestやテスト用モジュールが正しく使われていない箇所を検出できます。

テストコードで今まで型チェックを省略してきたので今後導入していきたい。

## 10.5 Typeguardによる実行時型チェック
> json.load() がAny型となってしまい、漸進的型付けの弊害がでました。実際のコードベースではよく起こる状況です。

こちらjsonをIFとしてやりとりしており、その通りなので導入したい。

## 10.6 まとめ
> リンタ型チェッカもエディタと統合するようにしてください。残念ながら、全員が使うべきエディタについては合意が得られていません。
> しかし、Noxのようなツールを使えば、チーム開発におけるローカル環境のベースラインを簡単に構築できます。

私のプロジェクトでは VSCode を使う前提である程度の自動化が組まれていますが今回の書籍をベースに採用可否含め検討したい。

さらに新たな知見や知識の補強もできたのでためになりました。