はじめに
Repository
Pythonの依存管理:uv lock / uv sync と従来の venv + pip の比較
Pythonでプロジェクトを開発する際、依存関係の管理や仮想環境の扱いは悩ましい問題です。最近では pyproject.toml を中心にしたモダンな管理方法が登場しています。その代表例が uv コマンド です。
1. 従来の方法:venv + pip
従来は以下のように管理していました。
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install fastapi uvicorn pandas nfcpy
pip freeze > requirements.txt
問題点
- 手動で requirements.txt を更新する必要がある
- 間接依存(uvicorn が依存する uvloop など)は自動で固定されない
- 仮想環境作成・依存インストール・同期を毎回手作業で行う必要がある
2. モダン方式:uv lock / uv sync
uv は pyproject.toml を中心に依存関係と仮想環境を管理するツール です。
pip + venv の操作を簡潔にまとめ、自動化しています。
pyproject.toml の例
[project]
name = "nfc-timecard"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
"nfcpy>=1.0.4",
"fastapi>=0.103.0",
"uvicorn[standard]>=0.22.0",
"pandas>=1.5.0"
]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
主要コマンド
| コマンド | 説明 | venv + pip での対応 |
|---|---|---|
uv lock |
pyproject.toml の依存関係を解析し、ロックファイルを生成。間接依存まで固定される |
pip freeze > requirements.txt に相当(ただし自動化される) |
uv sync |
仮想環境を作成(なければ自動)し、ロックファイルに従って依存をインストール |
python -m venv .venv + pip install -r requirements.txt に相当 |
3. 特徴とメリット
- 自動ロック
- 間接依存も含めて完全にバージョン固定
- 仮想環境自動作成
- uv sync 一発で .venv ができる
- pip freeze 不要
- ロックファイルを自動生成するので管理が楽
- pyproject.toml に依存を集約
- 開発者・CI/CD・デプロイ環境で同一依存関係を再現可能
4. まとめ
| 項目 | venv + pip | uv |
|---|---|---|
| 依存追加 | pip install X |
pyproject.toml に追記 |
| 依存固定 | pip freeze > requirements.txt |
uv lock |
| 仮想環境作成 | python -m venv |
uv sync が自動作成 |
| 依存インストール | pip install -r requirements.txt |
uv sync が一括実行 |
💡 結論
-
uv lock= 依存関係をロック(requirements.txt 相当) -
uv sync= ローカル環境に依存をインストール(pip install 相当) - pip + venv の作業を 自動化+再現性確保 したものが
uvというイメージです
uvインストール方法(Windows)
- Rust製の高速なPythonパッケージマネージャー
-
pipやpoetryより圧倒的に高速 -
重要:
pip install uvではインストールできません- Python(
pythonコマンド)やpip(pipコマンド)は、Pythonインストール時に自動的にPATHに登録されるため意識する必要がありません - しかし、uvはPythonとは独立したスタンドアロンツールなので、別途インストールしてPATHに登録する必要があります
- Python(
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
インストール後はPowerShell(やPyCharm)を再起動してください。以下で確認できます:
uv --version
uv 0.9.8 (85c5d3228 2025-11-07)
Get-Command uv
CommandType Name Version Source
----------- ---- ------- ------
Application uv.exe 0.0.0.0 C:\Users\XXXX\.local\bin\uv.exe
APIサーバを起動
uv run uvicorn app.main:app --reload
補足(OneDrive 環境での注意):
- プロジェクトが OneDrive 配下にある場合、
uvがハードリンクやクリーンアップで失敗することがあります。- 一時回避: 同じシェルで
UV_LINK_MODE=copyを設定してから実行$env:UV_LINK_MODE = 'copy' uv run uvicorn app.main:app --reload - 恒久設定: 環境変数を永続化して常にコピー方式にします(uv の
configサブコマンドが無い版でも有効)# 現ユーザーに永続(推奨) [Environment]::SetEnvironmentVariable('UV_LINK_MODE', 'copy', 'User') # または Windows 標準の setx を使用 setx UV_LINK_MODE copy # 反映には新しいターミナルを開く/再ログインが必要です - それでも
.venvの削除に失敗する場合(os error 5 など)は、OneDrive を一時停止してから.venvを作り直してください# OneDrive 同期を一時停止 → すべての python/uvicorn を終了 Remove-Item -Recurse -Force .venv $env:UV_LINK_MODE = 'copy' uv sync uv run uvicorn app.main:app --reload - より安定させるには、プロジェクトを OneDrive 外(例:
C:\dev\nfc-timecard)に移すか、対象フォルダを「このデバイスに常に保持」に設定してください
- 一時回避: 同じシェルで
NFCリーダー(PaSoRi)のセットアップ
Windows用ドライバ(WinUSB)のインストール
Pythonの nfcpy ライブラリでPaSoRiを使うには、WinUSBドライバに変更する必要があります。
Zadigとは?
- WindowsでUSBデバイスのドライバを変更できる無料ツール
- https://zadig.akeo.ie/
⚠️ 注意: Zadigでドライバを変更すると、Sony純正ソフト(FeliCa Port Softwareなど)が使えなくなる場合があります。元に戻すにはデバイスマネージャーから元のドライバに戻してください。
手順
- Zadig をダウンロード: https://zadig.akeo.ie/
- NFCリーダー(PaSoRi)を接続
- Zadig を起動 → Options → "List All Devices" をON
- デバイス一覧から NFCリーダー(
Sony RC-S380など)を選択 - Driver欄で "WinUSB" を選び Install Driver をクリック
動作確認
python -m nfc
「読取待ち」状態になればOK。うまくいかない場合はドライバ設定を再確認してください。
マイナンバーカードの制約事項
🚨 重要:マイナンバーカードはUID(固有識別子)がランダム化される
マイナンバーカードをNFCリーダーで読み取った際、個人を特定できる固定IDが取得できません。
実験結果
同じマイナンバーカードを3回タップした結果:
[DEBUG] Tag detected: Type4BTag
[DEBUG] Identifier (hex): 84E8FF18 [23:03:47] 84E8FF18 -> clock-in
[DEBUG] Tag detected: Type4BTag
[DEBUG] Identifier (hex): 7B9AFDAF [23:04:19] 7B9AFDAF -> clock-in
[DEBUG] Tag detected: Type4BTag
[DEBUG] Identifier (hex): C76FD9A0 [23:04:28] C76FD9A0 -> clock-in
同じカードなのに、毎回異なるIDが返される ことが確認できました。
技術的背景
- マイナンバーカードは ISO/IEC 14443 Type B 規格
- プライバシー保護のため、UID(カード識別子)がランダム化される仕様
-
tag.identifierで取得できる値は毎回変わるため、個人の特定には使えない
取得できた情報
python Tag attributes:
- TYPE: 'Type4Tag'
- identifier: b'\x84\xe8\xff\x18' # ← 毎回変わる!
- is_authenticated: False
- is_present: True
- ndef: None
- product: 'Type4Tag'
代替手段
マイナンバーカードで個人を識別するには:
- JPKI(公的個人認証)の証明書を読み取る(PINコード入力が必要、実装が複雑)
- カード内のアプリケーション領域にアクセス(APDUコマンドで通信、高度な実装が必要)
結論と推奨
勤怠管理システムでマイナンバーカードを使うのは不向きです。
代替案:
- ✅ 交通系ICカード(Suica、PASMO等): 固定UIDを持ち、簡単に個人識別可能
- ✅ 社員証(Felica/MIFARE等): 企業で発行されるICカード
- ✅ 専用のNFCタグ: 安価で固定ID付きのカードを配布
本プロジェクトでマイナンバーカードを使う場合は、環境変数 ACCEPT_ALL_TAGS=1 を設定し、デモ/検証目的として利用してください。実運用では別のカードの使用を強く推奨します。
検証結果:PASMOでの動作確認 ✅
マイナンバーカードでは識別子がランダム化される問題があったため、PASMO(交通系ICカード) で検証しました。
実行結果
NFC watcher starting... (Ctrl+C to exit)
[23:16:42] 01010A10XXXXXXXX -> clock-in | in=2025-11-12 23:16:42.995179 out=None hours=None
[23:16:50] 01010A10XXXXXXXX -> clock-out | in=2025-11-12 23:16:42.995179 out=2025-11-12 23:16:50.359021 hours=0.0
⚠️ セキュリティのため、カードIDの一部をマスキングしています
マイナンバーカードとの比較(デバッグモードでの検証)
PASMO(Type3Tag / FeliCa)
[DEBUG] Tag detected: Type3Tag
[DEBUG] Identifier (hex): 01010A10XXXXXXXX
2回目も同じID
[DEBUG] Identifier (hex): 01010A10XXXXXXXX ✅ 固定
マイナンバーカード(Type4BTag)
[DEBUG] Tag detected: Type4BTag
[DEBUG] Identifier (hex): 84E8FF18
# 2回目は別のID
[DEBUG] Identifier (hex): 7B9AFDAF ❌ ランダム化
# 3回目もまた別のID
[DEBUG] Identifier (hex): C76FD9A0 ❌ ランダム化
結果
- ✅ PASMO: 同じカードで同じIDが取得できる(
01010A10XXXXXXXX) - ✅ 出勤→退勤のトグル動作が正常に機能
- ✅ 勤務時間の計算も正確(8秒間 - 休憩1時間 = 0時間)
- ❌ マイナンバーカード: 毎回異なるIDが返される(個人識別不可)
カード種別の比較表
| カード種別 | タグタイプ | 識別子の安定性 | 勤怠管理での利用 |
|---|---|---|---|
| PASMO/Suica | Type3Tag (FeliCa) | ✅ 固定ID | ✅ 推奨 |
| マイナンバーカード | Type4BTag | ❌ 毎回ランダム化 | ❌ 不可 |
技術的背景
マイナンバーカードがランダム化される理由:
- ISO/IEC 14443 Type B 規格に準拠
- プライバシー保護のため、UID(Unique Identifier)が意図的にランダム化される
- カード内の個人情報にアクセスするには、APDUコマンドとPINコードが必要
PASMOが固定IDを持つ理由:
- FeliCa (Sony) 規格に準拠
- 交通機関での高速処理のため、固定IDによる即座の識別が必要
- IDm(製造番号)が固定値として設定されている
結論
交通系ICカード(PASMO、Suica等)は勤怠管理システムに最適です。FeliCaベースのカードは固定IDを持つため、安定した個人識別が可能です。
