PyPIのTOP 4000 パッケージのsdistをダウンロードする

Deprecate済みの機能をそろそろ削除していいかどうか悩んだときに、Githubソースコード検索だとソースコードのコピーが置いてある個人リポジトリがたくさんあったりして役に立ちません。

PyPIのミラーを作って全部のパッケージを確認できればいいのですが面倒なので、とりあえずTOP4000パッケージだけを対象にしてソースパッケージのダウンロードして調査しています。

まずTOP4000パッケージのリストですが、 Top PyPI Packages というサイトから入手できます。BigQueryで自分でリストを作るよりもお手軽です。

hugovk.github.io

つぎにパッケージをダウンロードする方法ですが、 pip download だと --no-deps つけてもビルド依存関係を解決しようとしたりしてうまくいかなかったので、PyPIJSON APIからsdistを見つけてダウンロードするようにしています。

notes/download_sdist.py at master · methane/notes · GitHub

Python/C API を調べたかったのでこのスクリプトは sdist しかダウンロードしていませんが、 Universal wheel しか配布していないパッケージもあるので、Python標準ライブラリの利用状況を調べたい場合は sdist が存在しない場合に wheel をダウンロードするように改修する必要があります。

sdist の拡張子は .tar.gz, .tar.bz2, .zip なので、あとは単にシェルの機能を使って展開するだけです。

他にもいい方法ないかなと思ったら、 Sourcegraph が結構使えそうでした。これは PyEval_ReleaseLock というDeprecateされている関数の利用例をSourcegraphで探す例です。

PyEval_ReleaseLock file:… - Sourcegraph

PEP 8騒動について

今週PEP 8の小さい変更についてMLで騒動が起こってしまいました。

該当のコミットはこれです。

PEP 8: Change requirement to adhere to Standard English (#1470) · python/peps@0c6427d · GitHub

変更点はごくごくシンプルなものです。

- When writing English, follow Strunk and White.
+ Ensure that your comments are clear and easily understandable to other
+ speakers of the language you are writing in.

今まで知らなかったのですが、変更前の "Strunk and White" とは The Elements of Style というすごく有名なライティングに関する本らしいです。

www.amazon.co.jp

この変更は "Strunk and White" を知らない人にとって分かりやすくなるようにする変更で、これだけなら論争が起こることはなかったのですが、コミットログでこの変更がBLMの動きに関連づけられてしまったために論争が起こってしまいました。

Instead of requiring that comments be written in Strunk & White Standard English, require instead that English-language comments be clear and easily understandable by other English speakers.

This accomplishes the same goal without upholding relics of white supremacy. Many native English speakers do not use Standard English as their native dialect, so requiring conformation to Standard English centers whiteness in an inappropriate and unnecessary way, and can alienate and put up barriers for people of color and those whose native dialect of English is not Standard English.

This change is a simple way to correct that while maintaining the original intent of the requirement.

最初の段落はいいのですが、次の段落の冒頭の "This accomplishes the same goal without upholding relics of white supremacy." でまずギョっとします。

White=善/Black=悪というバイアスを強化する用語は、たとえ肌の色を意味していなくても排除しようという運動があり、最近は blacklist/whitelist に対する word policingが大きな話題になりました。そんな背景があったので、 "Struck & White Standard English" の White はもちろん著者の人名なんですが、まさか人名のWhiteすらword policing対象になるの!?と反射的に思ってしまう人がいました。

もちろん人名が問題になっているわけではありません。 Strunk & White Standard English は白人優位な社会で生まれた白人の標準語で、その利用を推奨することは黒人英語(AAVE)などの方言が標準英語ではないんだ、白人英語の方が標準(=優位)なんだというバイアスを助長するのが問題だとされています。とはいえ、コミットコメントでは Strunk & White がなぜ白人優位なのかの説明が抜けているので、まさか名前が問題なの?という誤解の原因になっています。

もう一つ論争になってしまっているのは標準語の利用を推奨するかどうかで、結局 "clear and easily understandable to other speakers of the language you are writing in." を達成するには標準的な一つの方言を使うしかないんですよね。あちこちの英語の方言が混ざると読みにくく、わかりにくくなります。それに英語ネイティブじゃない人に英語の読み書きを強制させることは英語=Standard、英語社会優位のバイアスを強化してしまってることには変わりありません。


PEP 8は本来Pythonの標準ライブラリのためのコーディング規約なので、結局Python開発に参加するときにアメリカの白人英語を使うことに変わりはありません。とはいえPEP 8はPython標準ライブラリに限らず広く使われているので、白人英語に限定した表現をせずに "clear and easily understandable to other speakers of the language you are writing in." という書き方にする変更自体は良いと思います。

とはいえ、このコミッターとGuidoだけで、他のコミッターに説明なくPEP 8が更新されたために、「Whiteっていう人名すらダメなの?」とか「方言使うことを推奨するの?黒人英語だけじゃなくて○○方言は?そもそも英語じゃない言語は?」っていう不要な誤解に基づく論争が生まれてしまいました。

今は git のヒストリを書き換えて、この誤解を招くコミットログをもっと誤解を生まない表現に修正するかどうかが話し合われています。

Python 3.10 の開発(お掃除)に参加しよう

訂正

昔から deprecate されているのにずっと生き残ってるヤツたちはクセモノのぞろいで、全然初心者向けではありませんでした。

代わりに、Docディレクトリを deprecated-removed::grep して、 3.10 で削除する予定になっているものを削除する方がずっと楽なので、そちらに挑戦してみてください。削除する手順は下の記事のままで大丈夫です。


Python 3.9 がベータに入り、masterブランチはPython 3.10の開発に入りました。

はっきりとした区分はないものの、Python 2.7との互換性のために長くdeprecated状態を維持していたメソッドの削除に踏み切るバージョンになりそうです。そこでこんなIssueを作ってみました。

Issue 41165: [Python 3.10] Remove APIs deprecated since Python 3.3 - Python tracker

新しいAPIを提案するよりもずっとハードルが低いはずなので、他の削除プルリクエストを参考にしてお掃除に参加してみませんか?

DeprecatedなAPIを削除する手順は次の通りです。

  1. (初めてプルリクエストを作る場合) CLA にサインする。
  2. ドキュメントでdeprecatedになったタイミングと、DeprecationWarningを出すようになったタイミングが十分(後述)に古いか確認する。
  3. 該当のAPIを削除する。該当のAPIからしか使っていなかったprivateメソッド等も同時に削除すること。
  4. テストも削除する
  5. NEWSエントリとwhat's newエントリを書く
  6. プルリクエストを送る

Pythonの最低deprecation期間は2バージョンですが、消すのを先延ばしにするデメリットが大きくない場合や古くから存在するAPIについては、それよりも長めのdeprecation期間があったほうがいいです。

既に Issue のコメントではPython 3.3時点でdeprecateされたものをリストアップしていますが、もう少し新しいdeprecationを探す場合も3.6までにdeprecationされてるものを選んだ方が「まだ消さないで」と言われるリスクは低いと思います。

PEP 623: Remove wstr from Unicode について

今週新しいPEPを作りました。 www.python.org

背景

Python 3.3からUnicodeの内部表現が変わり、文字列に含まれる最大のコードポイントから1byte(ASCII or latin1), 2byte (UCS2), 4byte (UCS4)を選ぶようになっています。 (PEP 393 Flexible Unicode Representation)

それまでのPython 2 やPython 3.2までは、Unicodeの内部表現はUTF-16UTF-32コンパイル時に決定されていました。(narrow build, wide build と呼ばれていました) この時に一文字を表すC言語の型を Py_UNICODE として、UTF-16なら16bit、UTF-32なら32bitの符号なし整数型が使われていました。

昔の内部表現を Py_UNICODE* 型で取得するAPI (PyUnicode_AsUnicodeなど) や、文字列を作成するときに先に Py_UNICODE の長さを指定してアロケートするAPI (PyUnicode_FromUnicode(NULL, length)) などを動かすために、今の実装は typedef wchar_t Py_UNICODE した上でUniocodeオブジェクトの内部に wchar_t *wstr というメンバーを持っています。

これにより、小さいASCII文字列でも64bit環境では wstr のために8バイトを消費しています。非ASCII文字列ではwchar_t (UTF-16UTF-32)にエンコードしたときの長さのために ssize_t wstr_length というメンバーもあり、合計で16バイトを消費しています。

言うまでもなく文字列(Unicode)オブジェクトはPythonで最も大量にインスタンスが生成される型の一つなので、ほとんどの文字列がASCIIだとしても1インスタンスあたり8バイトの消費はそろそろ削りたいです。

削除に向けて

残念ながらいくつかのAPIがドキュメントではDeprecatedと書かれているものの、CコンパイラーのWarningを出すようにはなっていなかったので、すぐには消せません。 実際のところ、特にWindows関連のライブラリで引数を wchar_t* で受け取るのが便利だったので、標準ライブラリの内部でもまだまだ使われてしまっていました。

コンパイラーのWarningを抑止するマクロを併用することで、これらの内部利用されているけれど消したいAPIにWarningをつけ、これは Python 3.9 にバックポートしました。 ただ、引数を解析する関数 (PyArg_ParseTupleなど) が wchar_t* を使ってる部分は関数自体をWarning対象にはできないので、実行時にPythonのDeprecationWarningを出す必要があり、これは現在ベータになっているPython 3.9にはバックポートできません。 wstr を利用している全てのAPIや動作のDeprecationができるのが3.10になります。

PEP 623では、通常のDeprecationプロセスの最短である Python 3.12でwstrを削除することを提案しています。

影響度

このプランが現実的かどうか調べるために、PyPIのダウンロード数トップ4000のパッケージから、ソースパッケージ (.tar.gzなど) を提供している物を全てダウンロードし、これらのAPIの利用状況を見てみました。

一番多かったのがCythonが生成したコードが空文字列を作るために PyUnicode_FromUnicode(NULL, 0) を使っているもので、これはもう直してもらいました。また同じくCythonがもっとレアな条件で PyUnicode_FromUnicode を使っているのも見つけ、これも報告してあります。次のCython (0.29.21) では直っていると思うので、あとはいろいろなプロジェクトが新しいCythonを使って生成したコードをリリースするのを待てばほとんどが解消されるはずです。

他に多かったのが、(Cythonが生成したコードを含めて)Python 2に対応するために #ifdef で区切ったコードで、Python 3では使われないものです。

Cython生成コード意外で問題になるコードを含むプロジェクトは多分20前後で、ほとんどは簡単なものだったので既にプルリクエストを出したり報告して修正してもらったりしています。なのでこの変更はそれほど大きい breaking change にはならないと考えています。

バグがあっても接触確認アプリをインストールしてほしい理由

3行サマリー:

  • アプリではなくOSが接触履歴を取っている
  • 今のアプリはOSの接触履歴をONにするだけ。バグがあっても使わなければ問題ない
  • (特に東京では)今週の接触履歴が今後役に立つ可能性がある

とうとう接触確認アプリが公開されました。これで今までよりも圧倒的に効率的に、陽性者の接触者に検査を受けてもらうことができるようになるかもしれません。ワクチンが開発されるまでの間、コロナと戦うための最大の武器になるかもしれません。

www.mhlw.go.jp

しかし、Bluetooth が有効になってないと起動しない、利用規約に同意しないでアプリを終了しても同意したことになってる、などのリリース前の準備が明らかに不足してるであろう問題が報告され、炎上しています。

大前提として、これらのバグの責任はもちろんリリースした厚生労働省とその委託先の会社、そしてリリースを急がせた政府にあり、ベースとなったOSSの開発者には一切責任はありません。

ただ、普通ならリリースするべき状態ではないアプリだったとしても、特に外で人と接する機会のある人には早めにインストールして欲しいと思っています。

今回の接触確認アプリは、消費電力やプライバシーのことを考えつつ、GoogleAppleAndroidiOSに実装した接触履歴の機能を利用しています。*1 この機能を有効にするには、政府公認のアプリをインストールする必要があります。そのためにアプリをインストールしてほしいのです。

一度接触確認アプリを起動してOSの機能を有効にしたら、その後はもうアプリを起動する必要はありません。アプリではなくOSが接触履歴を取ってくれています。OSの機能さえ有効にすれば、今はアプリは使わなくても良いのです。 *2 私はリリース直後にインストールしましたが、このアプリはなんの権限も要求せず、バックグラウンドの動作時間が0で、通信量も電池消費も0です。全く動かさなくていいアプリのバグを気にする必要があるでしょうか?

将来アプリの新しいバージョンがリリースされて、バグが修正され、陽性者報告が動き始めたときに、接触履歴がOSにあれば陽性者との接触を教えてくれたり、自分が陽性になったときに接触した人にそれを(なるべくプライバシーに配慮した形で)伝えられるのです。今日接触履歴を取り始めないと、後でだれかの陽性がわかったときに今日の接触者を探すのが困難になるのです。

「アプリにバグがあったらインストールが敬遠されて逆効果じゃないか!」という意見は正論ではあるのですが、声高に問題を叫ぶことも同じくインストールを敬遠する人を増やします。 攻撃的な批判は、アプリのバグと同じくらい悪い効果があるのです。

攻撃的な批判ではなく、問題の回避方法とか、「起動できない人はアップデートを待ってね」と、インストールするモチベーションをなるべく下げない言い方で意見表明して欲しいと思います。

現在東京は一日に30人前後の新規陽性者が確認されている状況です。新型コロナは潜伏期間が長いので、今一日100人、200人が新規感染していて、それが2週間後に新規陽性者数として現れてくるかもしれないのです。そのときに陽性者報告が動き始めたとして、今週からの接触履歴があるのと無いのとでは大きな差になりえます。

このように、本来あと1週間か2週間かけて準備するべきリリースを前倒ししたことには十分な意義があったと思います。(それを説明する責任は政府にあると思いますが)

*1:すでに接触確認アプリを使ってる国で消費電力やプライバシーが問題になっているのは、GoogleAppleの実装を待たずにアプリで接触履歴を取っているからです

*2:アプリの役割である陽性者報告がまだ動いてないので、そもそもOSの機能を有効にする以外の使いみちはまだありません

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。