nikkie-ftnextの日記

イベントレポートや読書メモを発信

皆さんに教えていただいた、uvで管理するPythonプロジェクトで使っているタスクランナーたち

はじめに

シリタイ!シリタイ!シリタイ!オシエテ? nikkieです。

こちらのツイートをしたところ、uvと一緒に使っているタスクランナーを多くの方から教えていただきました。
ありがとうございます!!

自分用整理のためにここに書き出します

目次

私はMakefile

mise(タスクランナー機能がある!)

一番驚いたのがこちら。

mise.tomlに書いたり、実行可能なファイルとして作ったりできるんですね!

miseでuvを入れて、uvでPython環境を整える。
uvにないタスクランナーはmiseで提供。
結構きれいかも(きゅん)

Taskfile

YAMLで書けるタスクランナー

Justfile

プロジェクトでTaskfileと使い分けている方も

taskipy

uvともいけるのか〜!

たしかにuv run task test、できました! おお〜

cargo-make

Makefile.tomlを書いて、cargo makeと使えるようになるんですね

runme

マークダウンの中のコードブロックを実行できるのか〜!(uvとの関連性は薄いかも)

終わりに

「みなさんどうしてますか?」と聞いたら、たっくさんのタスクランナーを知る機会となりました。
本当にありがとうございます。
アウトプットする者に情報は集まるの例ですね。

琴線に触れたもの

  • mise -> uv -> python。そしてmiseでタスクランナー!
  • uv run task test(taskipyとの再会)

Astral社がuvのタスクランナー機能の開発優先度を上げていないように見えるのは、代替手段が豊富にあり、そこをuvで統一することは考えていないから、なのかもしれないですね。

uvで管理するPythonプロジェクトにタスクランナーが欲しいのですが、みなさんどうしてますか?

はじめに

ここにいる2年と3年、そしてきっと、滝先生も思ってる。なんでだよって。 nikkieです1

uv使ってる各位、タスクランナーどうしてますか?
イチオシのタスクランナーがあったらぜひ教えてください

目次

前提:uvで管理するプロジェクト

uv initでappまたはlibとしてPythonプロジェクトを始められます。

このPythonプロジェクトのルートにはpyproject.tomlが置かれます(uvが見ています)。
テストや静的解析など開発時のみ使うパッケージは、uvがいち早くサポートしたDependency Groupsとして書いてもいいですね(uv syncコマンドの--group)

テストに使うpytestや静的解析ツール(Ruffやmypyなど)を、コマンドラインでの引数をはしょって呼び出したくなります(開発中、何度も何度も動かしますからね)。
他の言語の例ではnpm scripts。
uvを使っているときに、npm scriptsのような機能(=タスクランナー)がほしいと私は強く感じます

実装はよ

2024年8月に開かれたissueは、2月頭時点でもOpenのままです

多くのuvユーザが待っていると思うんですが、半年間でも設計には足りなかったのでしょうか?

(ぶっちゃけ私はAstral社に対応する気がないとまで思ってしまっているのですが、状況に詳しい方がいたらぜひ教えてください)

私はMakefile

やむなく私はMakefileを書いています2。

  • pytestはテストコードでimportして使う(フィクスチャなど)ので、Dependency Groupsを使用
    • uvが管理する仮想環境に加えており、uv runで実行する
  • Ruffやmypyはソースコードではimportしない
    • 好みだが、uvx(やpipx run)で(開発者が管理せずとも)最新に保ちながら使う
  • Ruffのフォーマットはformatとcheck --fixの2コマンドになる3ので、Makefileで1コマンドにまとめた

uvで管理するPythonプロジェクトには、おんなじようなMakefileが置かれるようになり、あんまり美しい解決策じゃないなあと感じています

pyproject.tomlに書いてコマンドを短くすればいいってこと?

Ruff, mypy, pytestコマンドの引数は、pyproject.tomlの[tool]テーブルに書けます。

たしかにこれでコマンドは短くなります。
ただ何回も打つものですし、Ruffによるフォーマット変更は1つにまとめたいので、make fmtと複数コマンドをより短くまとめられる方が私には嬉しいです

他のツールの例

taskipy

好みのツールです。
uv(など)を使わず、素の仮想環境を私がパッケージマネージャの最後のピースとして操作していた時期に使っていました。

task testのようにコマンドをまとめられます!
フック(例:pre_test, post_test)によってタスクを繋げられる点がとても気に入りました。

なお、「実装はよ」で取り上げたuvのissueから既存ツールが知れます(awesome Python task runner状態)

Hatch

hatch fmtやhatch testがあります。

(uvが1つの仮想環境に対し、)Hatchは用途ごとに分けた複数の仮想環境を作ります。
上のコマンドも内部にフォーマット用の環境、テスト用の環境を持ちます(hatch env show --internalをどうぞ)。
さらにhatch run(またはhatch env run)で環境を指定して、定義したスクリプトを実行できます!
これはかなりnpm scriptsに近い印象です

Poetry

登場時は革新的でしたが、今は標準に追従できていない感のあるPoetry4。
Poetryにもタスクランナー 勝手に愛称「ぽえぽえ」があると聞いています。

終わりに

現在のuvに不足している感のあるタスクランナー機能と、その実現方法を書きました。

  • やむなくMakefile
    • 開発中に何回もやるuv runやuvxは毎回引数込みで打つのではなく、短いコマンドにして実行したい
    • またRuffを1コマンドにまとめたい(hatch fmtとてもありがたい)
  • pyproject.tomlにツールの設定を書いて、一部の引数を不要にできる
    • 残る引数がある & 1コマンドにまとめたい -> 私の場合、Makefileを置き換えられなかった

ここはコミュニティのニーズと、Astral社の認識に大きなギャップがあるように感じています。
マジでみんな(特にuv推進派の方々)、やり方教えてほしいなア!!

P.S. uvはbuild backendを自前で実装したいみたい

uv should provide its own build backend.

最近のリリースにpreviewとして入ってきています。
しかし私が喉から手が出るほどほしいのは、タスクランナー機能なんですよ(uv should must provide task runner feature!)


  1. 響け!ユーフォニアム 3期10話。私も思ってることを話します!↩
  2. ptw ↩
  3. ↩
  4. 2025年時点では、Poetryよりは、Hatchやuvを私は薦めます↩

Python開発に使うツールの設定値は、pyproject.tomlに書けます!

はじめに

今日(2/3)は節分ですね! nikkieです。

pyproject.tomlの好きなとこの1つを紹介します。

目次

前提:pyproject.tomlを置いたPythonプロジェクトの話です

私の3類型によると

3️⃣再配布するプロジェクトが今回の話に該当します。
2️⃣再配布しないプロジェクトにも、ツールを設定するためにpyproject.tomlを置いてもよいと思います1。

pyproject.tomlのtool table

pyproject.tomlとは
https://packaging.python.org/en/latest/glossary/#term-pyproject.toml

The tool-agnostic Project specification file.

意訳ですが「ツールを知らなくてもよいプロジェクトの仕様ファイル」

PEP 518で定義されています。

今回取り上げるのは「tool table」!2
https://peps.python.org/pep-0518/#tool-table

The [tool] table is where any tool related to your Python project, not just build tools, can have users specify configuration data as long as they use a sub-table within [tool],

過去記事ですが、taskipyというツールで[tool.taskipy.tasks]と設定していました。

先人の記事「その設定、pyproject.tomlに全部書けます」

上で示したtaskipyのような[tool]テーブルの設定例を示した記事がこちら

  • flake8
  • black
  • isort
  • mypy
  • pytest

のテーブルの書き方例を示しています👏

この記事をきっかけにmypyやpytestはドキュメントにあたって書いてますね。

もちろんRuffの設定もpyproject.tomlに書けるぜ!

ズバリなドキュメント

私はRuffを

% uvx ruff format
% uvx ruff check --fix --extend-select I

で使っています(プロジェクトにインストールしてuvxなしで使うこともできますね3)。
この記事のexample.pyを今回も動作確認に使いました。

ruff checkコマンドの引数をpyproject.tomlに書くと

[tool.ruff.lint]
extend-select = ["I"]

これを置いたディレクトリにて

% uvx ruff check --fix

--fixは指定します4。
(未使用変数についても自動修正させたいなら--unsafe-fixesも指定)

終わりに

Python開発に使うツールの設定値は、pyproject.tomlの[tool] tableに書けます!

この記事で設定できると言及したツールたち

  • taskipy
  • flake8
  • black
  • isort
  • mypy
  • pytest
  • Ruff

ツールの設定値をpyproject.tomlに書いておくと、複数人での開発で設定が共有されるのが個人的には好みです。
またOSSのライブラリの[tool] tableめぐりは発見につながることがあり、小さな楽しみでもあります。
ありがとう、PEP 518🫶

P.S. 無視された例😱

hatch testはpytestを実行するのですが、(以下記事執筆時のバージョンでは)[tool.pytest.ini_options]を見てくれませんでした


  1. 1️⃣スクリプトは単一ファイルですから、使うツールも限られるのではないかと思います(例えばスクリプトにpytestは私は使いません)。ツールがサポートするなら、グローバルな設定ファイルを試すというアイデアが浮かびました(が私は検証するほど困っていません)↩
  2. プロジェクトのメタデータもpyproject.tomlには書けます ↩
  3. Ruffは開発中のコード内でimportしないのでuvxで最新バージョンを楽に使いたい派です↩
  4. ドキュメントによるとRuffはデフォルトでfixable = ["ALL"]。すなわち、--fixを指定したら全てのルールを修正する設定↩

nikkie v2025.01 リリースのお知らせ

はじめに

幕が上がる瞬間が好き♪ nikkieです。

1月のふりかえり記事です。
12月はこちら

目次

1日1エントリ継続中

800日を超えました。
読んでいただきありがとうございます!

技術まわり

ちょww俺有名人じゃんwww

1月のハイライト。
14万回表示とかいくんですね

お正月に技術アウトプットは読まれる説

目を引くんでしょうか

browser-useきっかけでGeminiを触る

browser-use自体はGPT-4oでまず開発しているようなのですが、「Geminiで動かせるかな」と手を動かしました。

GeminiのAPIやSDKは整理できました(しかしGoogleさん、散らかし過ぎな気が...)

browser-useが依存しているMainContentExtractorの作者様を知れたぞ🙌

技書博で無を頒布

落としたのはこれで3回連続(12月のふりかえり参照)。
技術同人即売会当日という締切に間に合わせられないのなら、辞めたほうがいいかもという思いがよぎります。
次に出たくなった際はブログの書籍化を試せるかも

色を出す

1月は Today I Learned な記事以外も書いてみようと、自分の考えをひっそりと出してみました。

Astral、爆速なツールを作り出したところはすごすぎるのですが、ちょっと思うところもあるんですよね(詳しくは続くシリーズにて)

OSS

仕掛け人活動として公開(お誕生日おめでとうございます!)

SpeechRecognitionは「何もしてないのに壊れた!」に見舞われつつ、2回リリース

(特に3.14.0の)裏話

inline script metadataを広めています!

サブカルまわり

ラーメン赤猫や、前クールからのアオのハコも楽しんでいますが、こちらを取り上げます。

メダリスト

新宿駅や渋谷コラボも見に行けて最高でした。
いのりちゃんかわいい(エビフライ食べたい)

終わりに

nikkie v2025.01がリリースされました。

  • Twitterでいつもよりも注目を集めた月
  • browser-useきっかけで、GeminiのAPI(2つ)やSDK(3つ)の理解が進みました
  • アニメ メダリスト、めっちゃよいぞ

そして、次のバージョン(v2025.02)に向けての旅が続くのです!

広告を非表示にする

PyPIのTrusted Publishersを よ う や く 設定しました。APIトークンの管理不要でリリースできる!

完全に理解したこちらを解題します

PyPIのTrusted Publishersが影響するのは、PyPIにパッケージを公開しているPython使いです。
APIトークンを使う方法から切り替えるのをおすすめします。

目次

これまで:PyPIのAPIトークンを使って、GitHubでリリースを作ったらPyPIに公開!

こちらの記事に書いています。

GitHub Actionsの抜粋です。
https://github.com/ftnext/sphinx-revealjs-copycode/blob/v0.1.0/.github/workflows/publish.yml

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      # 省略
      - name: Publish package
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}

これから:PyPIでTrusted Publishersを設定!!

これまでの方法からAPIトークンが不要になります。
GitHubでリリースを作ったらPyPIに公開されるのは変わりません。

もともとAPIトークンの管理を煩雑に感じていました。
上記記事の「ちょっとしたお悩み:Actionのシークレットは2回設定しています」より

  • これから初めてPyPIに公開する場合、PyPIにプロジェクトがないのでスコープをやむなく「アカウント全体(全プロジェクト)」にしています
  • PyPIへの初回公開が成功した場合、スコープをプロジェクトに絞ったトークンを再度作り、シークレットの設定値を更新します

Trusted Publishers自体は聞いたことはありました。
ただどういうものかがよく分からず、設定を後回しにしてきました。
やってみた今なら言えます、設定はPyPI上でフォーム入力だけ! APIトークンが不要になってめっちゃ便利!

既存のプロジェクト

公式ドキュメントは画像付きで参考になります(英語ですが、翻訳と合わせて)

  1. PyPIで既存のプロジェクトにアクセス
  2. プロジェクトのサイドバーからpublisherを追加

なんと、これだけです!

(GitHubのリポジトリ以外からもpublishできるようですが、今の私は使わないので取り上げていません)

新規プロジェクト

こちらも公式ドキュメントに画像があります

https://pypi.org/manage/account/publishing/ からpending publisherを追加します

  • PyPIのパッケージ名
  • publishするGitHub Action
    • 既存プロジェクトと同じ項目です

GitHub Actionsから初回公開できると、通常のpublisherとなりました

GitHub Actionsの変更

上記の抜粋を変更して示します

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
+    environment: pypi
+    permissions:
+      id-token: write

    steps:
      # 省略
      - name: Publish package
        uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          password: ${{ secrets.PYPI_API_TOKEN }}
  • environmentがPyPIのpublisherのフォームに入力したものです
    • GitHub Actionsって環境(environment)1って概念があったんですね
  • id-tokenがwriteできる権限2を付けます
    • 「OpenID Connect (OIDC) トークンをフェッチします。 これには id-token: write が必要です。」3
  • pypa/gh-action-pypi-publishアクションに渡すトークンは不要なので削除
    • passwordが指定されていないときtrusted publisherとして動くみたいでした。賢い!

例:https://github.com/ftnext/sphinx-revealjs-copycode/commit/9c479a1a40debbcdb0e4e7a3354a8346c48cc256

終わりに

「なんだかよく分からないな」と後回しにしていたPyPIのTrusted Publishersをついに設定しました。
設定だけなら簡単で、APIトークンの管理が不要になり、GitHubでのリリース作成を契機にGitHub ActionsでPyPIに公開し続けられています!

  • PyPIでpublisherを追加するフォームを入力(既存プロジェクトも新規プロジェクトも)
  • GitHub Actionsのワークフローを変更(environmentとpermissionsを追加)

みんなも設定しよう!

Trusted Publishersの仕組みにはOIDCなど絡むようで、今の私には「魔法のよう」を超える理解はありません(より安全になってるんだと思ってます)。
少しずつでも理解を深められたらと思います

広告を非表示にする

2/8(土)はPyCon mini Shizuoka 2024 continueですよ!「ライブラリ開発者に贈る『ロギングでNullHandler以外はいけません』」がついに日の目を見るぜ...! #pyconshizu

はじめに

行くぜ、shizu1 nikkieです。

タイトルが全てシリーズ!!

目次

台風で延期のPyCon mini Shizuoka 2024がついに振替開催!

2/8(土)、静岡で僕と握手!

タイムテーブルはこちら。
https://shizuoka.pycon.jp/2024-continue/info
私のトークはお昼の後の13:20〜ですね

ライブラリ開発者に贈る『ロギングでNullHandler以外はいけません』

なぜか? ーハンドラは(ライブラリ開発者のあなたではなく)ライブラリのユーザが決めることだからです

聞く方の想定:
「ロギング」とはなにか知っていて、Pythonのloggingモジュールを触ったことがある

このトークで目指すもの:
「Pythonのロギング、学習コストが高いし、実装に比べて調べきれないからもうlogging.warningでいいや」から卒業できる。
具体的には、ロガー、ハンドラ、フォーマッタ、フィルタといった概念を大まかに理解しましょう。

プロポーザルの詳細は以下をどうぞ(プロポーザル全文あります)

実はYouTubeでもう見られます!
進めていた発表準備を一度やり切ることにしたのです2。

裏番組の「Cloudflare WorkersにPythonがやってきた」(筒井さん)を聞きたい方は、YouTube公開版をどうぞ。
予習してトークに臨んで、発表者はタジタジさせるような鋭い質問も歓迎です(準備がんばるぞー!)

発表準備裏話

このエントリを書いたのは、この週末に準備を進捗させる勢いづけの意味合いもあります。
準備で参照したい事項をここに書き出し!

YouTube公開をしたことでいただいたフィードバックもありました(感謝)

また、私の知識も当時より深まっています。
1つがlogging.config

構成はプロポーザル準拠で、なのでYouTube公開版から大きく変えない内容を準備します。
ですが、説明の仕方は今の知識をふんだんに反映していきたいなと思っています。

終わりに

2/8(土)のPyCon mini Shizuoka 2024 continueで、Pythonのロギングの話をします。
静岡の地でお会いしましょう〜!

おまけ

ちょっと待って!旅マスのシャニマス期間じゃん!!
ナイスタイミングすぎる🤗

なお、ブッキングもある模様😭


  1. ええ、ジュリアさん (頭ミリオン)↩
  2. ↩
広告を非表示にする

WireMockをローカルのKubernetesで動かす 〜ちさたき移植を目指して、まずはDeploymentとService〜

はじめに

もしもしもしもし〜、nikkieです。

docker runで素振りした題材をKubernetesに移植する素振りです。

目次

WireMockをJSONファイルで設定してDockerで動かす

過去記事より

WireMockはAPIをモックできるツールです。
システムが依存するAPIを、テスト時にスタブ・モックにするシーンで使っています。
この素振りとして、過去にリコリス・リコイル1なWireMockを設定しました。

$ curl http://localhost:8080/chinanago
さかなー🐟
$ curl -s http://localhost:8080/takina -H 'Content-Type: application/json' -d '{"lines": "chinanago"}' | jq .
{
  "lines": "さかなー🐟"
}

たきなをGET、千束をPOSTで設定しました

WireMockのDockerイメージをrunしていたわけなのですが、ふと「Kubernetes(ローカルに用意)で動かせるのでは!?」と電波を受信しました。
設定するのを後回しにして、最初はKubernetesで動かすだけやってみます。

ServiceとDeployment

ローカル環境のKubernetesは、Rancher Desktopを使っています2(Version: 1.17.1)。
https://docs.rancherdesktop.io/#kubernetes

WireMockのイメージをKubernetesで動かすにあたり、このたび認識したのは、ServiceとDeploymentを定義する必要があるということ

Deployment

Deployment はPodとReplicaSetの宣言的なアップデート機能を提供します。

WireMockのイメージはPodとして動くわけですが、どんなPodを常に何個動かすか(ReplicaSet)をDeploymentとして定義するという理解です。
ドキュメントに沿って以下を用意

  • Deploymentの名前は.metadata.nameの「chisa-taki-deploy」
  • .spec.templateでPodを定義していると理解
    • .metadataでapp: chisa-taki-appとラベル付け
    • (さらなる).specでWireMockのイメージを指定し、8080ポートを設定しています

kubectl apply -fで適用します。

% kubectl --context rancher-desktop -n default apply -f deployment.yaml
deployment.apps/chisa-taki-deploy created

Service

KubernetesにおけるServiceとは、 クラスター内で1つ以上のPodとして実行されているネットワークアプリケーションを公開する方法です。

用意したWireMockのPodにリクエストを送りたいので、Serviceも作ります。

Kubernetesにおいて、ServiceはPodの論理的なセットや、そのPodのセットにアクセスするためのポリシーを定義します

  • Serviceの名前は.metadata.nameの「chisa-taki-svc」
  • .spec.selectorにあるapp: chisa-taki-appというラベルのPodの8080番ポートをターゲットにする(targetPort)
    • 気づき:ラベルでPodの論理的なセットを用意してるってことか!(複数Podがあってもこれならリクエストを送れそう)

今回nameを揃えずバラバラにしたのは、Deploymentで定義したPodに、Serviceをどのようにしてリクエストを送れるようにするのかを理解したかったという理由があります。

kubectl apply -fで適用

% kubectl --context rancher-desktop -n default apply -f deployment.yaml -f service.yaml 
service/chisa-taki-svc created

動作確認

Serviceをポートフォワードして確認します

% kubectl port-forward svc/chisa-taki-svc 8080:8080

WireMockは未設定ですが、スタブの設定を確認できるエンドポイントがあります3。
https://wiremock.org/docs/standalone/admin-api-reference/#tag/Stub-Mappings/operation/getAllStubMappings
GET /__admin/mappings

ここにリクエストを送って疎通確認とします

% curl 127.0.0.1:8080/__admin/mappings
{
  "mappings" : [ ],
  "meta" : {
    "total" : 0
  }
}

なお、GET /__admin/healthもありました。
https://wiremock.org/docs/standalone/admin-api-reference/#tag/System/operation/getHealth

% curl 127.0.0.1:8080/__admin/health 
{
  "status" : "healthy",
  "message" : "Wiremock is ok",
  "version" : "3.10.0",
  "uptimeInSeconds" : 144,
  "timestamp" : "2025-01-30T12:32:58.299082Z"
}

終わりに

WireMockをローカルのKubernetesで(設定は何もせずに)動かしました。

  • KubernetesのDeploymentとServiceを定義
  • DeploymentでPodにラベルを付け、そのラベルをServiceでも使いターゲットにした

ラベルの理解が少し深まったのが収穫です。
まだKubernetesではちさたきできていないので、今後は設定を探っていきます!

今回のソースコード


  1. おおお! ↩
  2. 他の方法でKubernetesを用意しても変わらないと考えています↩
  3. https://wiremock.org/docs/standalone/administration/#fetching-all-of-your-stub-mappings-and-checking-wiremock-is-working↩
広告を非表示にする