人様に見せられるコードを
自身用にpriave設定で使用していたgitリポジトリや、publicだけど自分でしか使うつもりのなかったコード。
人様につかってもらう前提のコード。
その間にはそれはそれは大きな隔たりがあるわけで。
、、と、ばかりも言ってられないので、自作コードを公開リポジトリにアップすべく、やらなきゃいけないことを考えてみました。
ターゲットはpythonのコードをpypiにアップすること。
。。。。「考える前に上げろ」。はい、まぁそれが正解なのでしょうけれど。
コードに関すること
1. 規約は恥ずかしくないくらいには守る
pycodestyleは通過させる。
pylintは、、、
2. Docstringをちゃんと書く
3. スペルミスを消し込む
ex"s"ampleとかやっちゃうんで。。
VSCodeを使っていればCode Spell Checkerというプラグインを導入するそうですが、viで書いている身としてはなんとも。
”これ!”というものも見つからないので少し試してみる。
aspell
Ubuntuで引っかかったのでaptで導入してみたが、、、
だめ。
pythonのパッケージ名が軒並みタイポで引っかかってしまって使い物にならん。。
pylint + enchant
apt-get install enchant
pip3 install pylint pyenchant
pylint --disable all --enable spelling --spelling-dict en_US test.py
だめ。pythonのstrの型や、argsに引っかかってしまう。
pylint --disable all --enable spelling --spelling-dict en_US --spelling-private-dict-file ./pdict --spelling-store-unknown-words y test.py
これだと、./pdictに検知したtypo候補が出力される。
これパット見るだけでパッケージ名や型とそれ以外は一目瞭然なので、これでいいかな。
pythonコードのあるあるdictファイルがあればそれを使いたいところだが、、ざっとググって見つからず。
まぁ、眼で見ればわかるかな。
変にインタラクティブに修正を問われるよりは、間違い単語だけ表示してエディタで手で直すほうがやりやすい気はする。
ただし、コメント部しか見ない(printの引数は見ない)というように、検査対象領域が明確に定まっているっぽい(調べきれていないけど、きっとpylintのページに書いてあるのであろう、、)。
また、camelCaseやsnake_caseについても、検出してくれない。
。。。トークナイズして、単語切り抜いて検査するスクリプトを自分で作ってしまう方が筋がいいのかもしれない。。
ライセンスに関すること
1. ライセンスファイルをちゃんと作る
そもそも、なんでライセンスを提示するのだろう?
自身のソースがどう使われるか(複写・改変・再配布)について特に制限をしたいという意図はないし、有償化するつもりもないので瑕疵担保免除の考慮もいらんけどなぁ(免責)というネガティブな感覚はありますけれど、まかり間違って自身のコードが他者に権利主張されてもめんどくさいし(著作権)、それよりなにより使う側もライセンスファイルも置かない人間が作るコードなんざ信用できんだろ、という気もしますから、まぁなんかしらちゃんとおいときます。
No Licenseという選択肢(はないですね。。)
https://choosealicense.com/no-permission/
ライセンスが明示しない場合、著作権が適用される。著作権が適用されると、複製・改変・再配布ができない。でもGITの公開リポジトリの場合は利用規約が適用されて表示やforkなどはできる。
。。forkの解釈の余地があるのかもしれませんが、軽くググるとforkは自分のアカウントにコピること、手元のPCにコピるのは「clone」なわけで、、
わざわざ怪しい解釈論考えるのも面倒ですね。
上記サイトに「ライセンスの明示されないコードは使うな!」と記載がある取り、あえて置かない理由もないですね。
ライセンスはどこに書く?
gitレポジトリのトップディレクトリにLICENSEを置くだけのものもあれば、1つ1つのコードの頭にライセンスの記載をしているものもあり、、って、、ん?
GNUは、、、よくよく読んだらEND OF TERMS AND CONDITIONSに「この条件有効化したいなら、ソースファイルの頭にこれ書きなさい」て書いてある、、、
MITは、個別のファイルにかけという旨の記載はないですね。改変・再配布を前提とするライセンスはソースがバラバラに切り貼りされ可能性があるからソース単位に記載が必要だけど、それがないMITはプロジェクトに1つ置いとけばいいや、、ということなのでしょうか。
他のライセンスも読み込むとおもしろそうだけど、それはまたの機会に。
いずれにせよ、ソース自体に明記が必要かどうかは、選ぶライセンス次第、てことですかね。
。。。そりゃMITが好まれるわけだ。
2. 著作権
まったく意識していなかった。。
むしろ自身の素性を如何に隠すか、という意識しかなかった。。。
ライセンスで権利を主張する以上、そりゃ権利主体がないとおかしいですわな。。
著作権はどこに書く?
MITライセンスだと、ライセンス文書の頭にブランクのcopyrightがあって、そこに書くみたいですね。
GNUは、ソースファイルの頭にこれ書きなさいフォーマットの中にコピーライト欄もありますね。
極論、コード公開しているgitのアカウントが著作権の保有者という解釈にはなるのでしょうけれど、ちゃんと書くか。。
3. importしているパッケージのライセンスを確認する
なんで確認するんだっけか、、
複製・改変・再配布の文脈でスタートしたのですが、、、これ複製でも改変でも再配布でもないですね。
私のパッケージが他のpackageに依存するとしても、依存パッケージは利用者が自身の責任で取得・使用することになるわけで、私が再配布するわけでも改変するわけでも無いですね。
コンパイルなりなんなりして、同梱配布したら当然話は違いますが。
強いていうと、改めて自分が使っているパッケージの利用条件を理解することと、へんてこな条件のライセンスをつかているものが混ざり込んでいないかの確認でしょうか(変な条件のパッケージを他者に使わせるわけにも行きませんし)。
どうやって確認するか?
pip-licenses: 良さげなのだが、現状の環境に入っているパッケージを全表示してしまう。そうではなく、アップするパッケージが使っているrequirments.txtだけ見てほしいんだよなぁ。
liccheck: iniファイルを最小作らないといけないのがなんとも、、
とりあえずpip-liceseとrequirements.txtを眼で流し読みするくらいで凌ぐかな。。
セキュリティに関すること
1. importしているパッケージのバージョン確認
そもそも、requirements.txtでバージョンはどう指定する?
そもそもrequrementsはなんのためのものか、、
自分のパッケージを動作させるために必要な他のパッケージとそのバージョンを示すものなわけですよね。
その前提で考えていきましょうか。
自身が開発に使ったバージョンからスタート
動作させるために必要な「バージョン」はというと、自分のパッケージの使う機能を保有しているバージョンですよね。
まず自身が開発時に使っていて、テストに通過できるバージョンを指定するところからスタートでしょうか。
例として、"hogehoge"パッケージ、バージョン"7.19.1"としましょう。
開発時のバージョン「以上」を許容する
で、バージョンを固定すると、そのバージョンに脆弱性があってバージョンアップしてくれてるのに、そちらを使えないということが起こるので、動作確認が取れているバージョン「以上」というように指定する、と。
requirements.txtには、hogehoge>=7.19.1とかく、と。
開発時のバージョン「以上」で許容の限界値を定める?
別の視点で、バージョンが上がりすぎて対象の機能が廃止になったり、引数仕様が変わったりなんかすると、動かなくなる、ってのもよくあるわけです(後方互換製のないバージョンアップ)。それを防ぎたいなら、利用しているパッケージの開発方針を調べて、自分が使う機能が仕様変更なく提供され続けるであろう範囲の「以下」にするように設定する、ってところですかね。
実際は、仕様変更縛りのルールをきっちり決めてない/遵守しないパッケージはいくらでもありそうなので、現実的ではないのかもしれませんね。。別途、後述の更新管理で考えたほうがいいのかもしれない。
仮に、2桁目のバージョン内では仕様は変えないと確認が取れたとすると、hogehoge>=7.19.1, <7.20でしょうか。
「指定以下」を許容する?
さて目線を変えて、パッケージを使う側から見ると。
お作法的には、各パッケージは常に最新にしておくもの。実際は、アップデートすればできるけどめんどくさいからあまりしてないってケースもあるでしょうけど。
あるいは、バージョン整合のトラブル起こしているパッケージのために、特定のパッケージだけあえて古いものを使う、ってのもあるのでしょう(2021.1現在でipythonがちょうどそんな感じですね、、)。
そういう人たちにストレスなく使ってもらうことを考えると、利用許可するバージョンは可能な限り広いほうがいい、、のかな。当然自分の使う機能が実装されている前までは許容できませんけど。
あるいはセキュリティ的に考えると、まずい脆弱性のあるバージョンの利用を許容しない姿勢を示すため、現実的な範囲で可能な限り新しいバージョンを使わせるよう指定するか、、。
結局どうする?
結局、以下の三択ですかね。
- "hogehoge>=7.19.0": 自身が開発で使ったバージョンについて、無理ない範囲で過去分に遡り、動作確認取れたものに対して「以上」で指定する。将来的にバージョンが上がり、仕様変わったもの使う人はエラーがでる。気にしないか、ちゃんとimportしてるパッケージのバージョンアップによる仕様変更は別の方法で検知し、速やかに自身のパッケージも更新すると覚悟を決める。
- "hogehgoe": 上記に加え、たまたまローカルでふっるいバージョン使ってる人でもエラーがでるけど、気にしない。
- "hogehoge>7.19.1, <7.20: 確実に動作すると確認できている/期待できるバージョンを指定し、条件に合わないときはインストール時点で失敗させる
最後の方法が親切な気もしますが、、、めんどい。
上2つの、エラーが起きたらユーザにクレームをgitに上げてもらう、というくらいの方がありがたい、、
ただし、”hogehoge"で指定する場合は、いざエラーが出たときに「製作者どのバージョンで動作確認取ったんだ?」というのがわからなくなりますから、1つ目のが妥当でしょうか。
引っこ抜く
とりあえず、ソースのあるディレクトリで叩いてrequirements用のベースを作るワンライナー。
$ find ./ -name "*.py" |
xargs -n1 egrep "^import|^from" |
cut -d " " -f 2 |
cut -d "." -f 1 |
sort | uniq |
while read PNAME; do
grep "^${PNAME}==" < <(pip3 freeze);
done |
sed -e "s/==/>=/"
pythonファイルを検索し、
import,fromの行を抜き出し、
頭のimport/fromを除去し、
hoge.higeのようにパッケージの子供だけimportしてる場合は親だけのこし、
uniq化して
pip3の結果と比較して
最後に==を=>に変更して、おしまい。
2. 静的コードチェック
静的コード診断。
ちゃんとやるならどこまでもやることはあるのだろうけれど、まぁツール上まずい結果が出ないようにしておきましょう。
$ pip3 install bandit
$ bandit -r <SRC Directory>
ちなみに自分のパッケージに対して実行したら、pickleのloadが危険、と指摘が出ました。
。。用途上如何ともしがたいんだよなぁ。。
、、、というようなリスクの需要をするためにも必要な手順ですわな。
3. Python2
え、、、考えるのめんどくさいんだけど。。
pipに上げる際に何かしら問題がある場合に考えるようにします。
機密情報に関すること
1. gitignore
当然入れるべきもの入れるのだけれど、、あくまで自動生成されるファイル群をはずすのが主眼っぽいので、本性の趣旨には微妙に合わない。。
https://github.com/github/gitignore/blob/master/Python.gitignore
https://www.toptal.com/developers/gitignore
2. 証明書/鍵系
割り切ってしまえば、拡張子ベースでcerでgrepするか、拡張子をつけずに使われやすいssh鍵についてはfileコマンドでファイルタイプをチェックしてprivate keyを探すか、でしょうか。。
何か良さげなライブラリなんかがあるといいんですが。。
とりあえずざっくりワンライナー。
$ find ./ -name "*\.(der|pem|crt|cer|key|p12)"
$ find ./ -name | xargs -n1 file | grep key
Commitしちゃってたら、以下。
$ git ls-files | egrep -i "*\.(der|pem|crt|cer|key|p12)"
$ git ls-files | xargs -n1 file | grep key
.ssh/id_rsa: PEM RSA private key
...
もし該当があってしまったら、gitから削除。
https://docs.github.com/ja/github/authenticating-to-github/removing-sensitive-data-from-a-repository
https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E6%AD%B4%E5%8F%B2%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88
実際には試してませんが、filter-branchか、bfgというツールを使うらしい。
https://rtyley.github.io/bfg-repo-cleaner/
(ちなみにpipでもbfgというものが引っかかるけど、これは全くべつものですね。)
あと、すでにpushしたことがあってしまったら、証明書全部取り直し。。絶対にそうなる前には防ぎたいですね。。
過去のコミットも含めるなら、以下。
$ git rev-list --all |
xargs -n1 git ls-tree -r --name-only |
egrep -i "*\.(der|pem|crt|cer|key|p12)"
fileコマンドを使う方法は思いつかず。
revisionごとにディレクトリを作って、その時点のファイル群をdumpする、、てのは、奥の手として用意しておく。こんな。
$ git rev-list --all | while read REV; do
git reset --hard $REV ;
mkdir /tmp/$REV
git ls-files | while read FNAME; do
cp --parents $FNAME /tmp/$REV/;
done
done
$ grep -nrIe <Keyword> ./
これで全文検索。
3. メールアドレス、アカウントなど自身につながる情報の精査
PII(Personally Identifiable Information)のキーワードでなにかしら妥当なツールがあってくれそうな気がするのだが、、オープンソースのものはないですね。。
これも、ワンライナーで頑張るしか無いのかな、、
$ grep -nrIe "[a-zA-Z0-9\-_\.]\+@[[a-zA-Z0-9\-_\.]\+"
過去のcommitも含めて確認する場合は、、下記でしょうか。
$ git rev-list --all |
xargs -n1 git grep -IE "[a-zA-Z0-9\-_\.]+@[a-zA-Z0-9\-_\.]+"
-Iでバイナリファイルを検査対象から除外。
-Eで正規表現で検索。
4. ログ・キャッシュ・一時ファイル
こちらはgitignoreをありがたく使わせてもらう、ですね。
https://www.toptal.com/developers/gitignore
あとは、git commitの前に中身を確認する癖をつけるか、でしょうか。
$ git add .
$ git ls-files
$ git rm <Target> --cached
で、.gitignoreを編集してからもう一週、と。
ログは、gitのログは後述します。
それ以外の一時ファイルなどのログは、上記で丁寧に調べるくらいしか思いつかないですね。
動作安定に関すること
1. テスト
pytest
pypiへのアップを考えるならpipの作りで開発することになるので、きちんとpytestが動作する状況を整えて、テストスクリプトをきっちり作りましょう。
でも、動作確認しながらコードを汲むフェイズでは、仕様もコロコロ変わるわけで、テスト自体もコロコロ変わるんだよなぁ。。
どのフェイズでしっかり作るかは悩ましいけれど、作ってしまえば安心してソースいじれるようになるのは事実なので、ある程度コード固まってきたらきっちり作る。
テスト駆動開発?プライベートのときは好きにやらせてくれ、、、
実際の設定は以下を参照させていただきました。
https://buildersbox.corp-sansan.com/entry/2019/07/11/110000
ただ、この手順だと一回pipを手元の環境にインストールしないとtestができない。
実際は、pip -e .で”editable mode"で一回インストールしてしまいさえすれば、その後同ディレクトリでコードを書き換えながらテストしてく分には違和感はないのだけど、、、
改めて、『インストールさせる前にテストで動作確認すべきだけど、動作確認のためにはインストールが必要で、、』と考えるとなんか変な気がしてくるなぁ。。。
ということでもうちょっと調査。
https://docs.pytest.org/en/stable/goodpractices.html
python -m pytest とすればインストールはしなくてもテストができるらしい。
試してみると、、ちと苦労した。。
$ cd ./src # pkgの親ディレクトリ
$ python3 -m pytest ../tests #testディレクトリ
pytestは-mで呼び出すと、実行したディレクトリをsys.pathに自動追加する。
なので、動作確認するパッケージの親ディレクトリで実行すると、./がimport で呼び出せるようになるので、テストが実施できると。
2. 環境依存性
もうそろそろめんどくさくなってきたけれど。
これはCIで吸収するべき分野ですね。
ただし、pythyonで作るくらいのスクリプトでCIでこってり管理する旨味も余り感じないので、最低限の作業で完遂させたい。
どうやらgithubには「Git Actions」という機能があるらしいので、とりあえずこいつで行ってみましょうか。
https://docs.github.com/ja/actions/learn-github-actions/introduction-to-github-actions
https://knowledge.sakura.ad.jp/23478/
githubの自分のプロジェクトページでActionsタブをクリックして作ってくんですね。
最終的にはプロジェクトの.github/workflowsの下に実行させたい内容を記載したymlを置いとくと、githubが勝手に解釈して、仕事してくれる、と。
name: Test on different environments.
on:
push:
branches: [ main ]
workflow_dispatch:
jobs:
test_ubuntu_18:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: |
python3 -m pip install --upgrade pip setuptools wheel
python3 setup.py pytest
test_ubuntu_20:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- run: python3 setup.py pytest
test_macos_10:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: python3 setup.py pytest
test_winsv:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- run: python setup.py pytest
試してみたら、結構トラブルが、、
ubuntu 16.04はエラーが出るのだけれど、あと2ヶ月でEOLするものに労力割くのもなぁということで、今回は無視。
環境差分対応のめんどくささの片鱗を早くもわからせられた気がしますね。。。
ちなみに実行環境(runs-on)は、stragegy.matrixをjobの下に配置することで、以下のようにもかける。
パット見スッキリするんだけど、、、これ実行失敗した環境があった場合他の環境の試験を実施せずにStopしちゃうみたいなので、切り分けがめんどくさい。
また、pythonがpython2になるバージョンとpython3になるバージョンとがあったりするので微妙に小細工を仕掛けないといけなかったりもするので、上記のように愚直に書くほうが無難かな。。
name: Test on different environments.
on:
push:
branches: [ main ]
workflow_dispatch:
jobs:
test_all:
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- run: python3 setup.py pytest
strategy:
matrix:
os: [ubuntu-latest, ubuntu-16.04, ubuntu-20.04, macos-latest, windows-latest]
用意されている環境は少々寂しいが、、、まぁいいでしょ。
自分でサーバ立てて、そこで実施させる「セルフホストランナー」という概念もあるようですが、そこら辺考えるのは真面目にCI環境が欲しくなったときですね。
Gitに関すること
あー、ようやく本題に入れるよ。。長かった。
1. アカウントの管理
人様に見せるコードは、やはり人様に見せないコードとは明瞭に区別して管理したい。
となると、やはり人様に見せる専用のgitアカウントを新しく作って、日頃使いのアカウントとは明瞭に分けてしまうこととする。
以下のように3アカ持つイメージ
- 人様に見せるアカ(prod)
- 人様に見せるアカの開発用アカ(stg)
- 日頃使いのアカウント
日頃使いのアカで作ってて、公開してもいいかなーというものができたときは整理の上、「人様に見せるアカの開発用アカ」にアップし、きれいにしてから、「人様に見えるアカ」へ。
こんな使い方かな。
メールアドレスとuser.name/user.emailの考え方
gitアカはメールアドレスと1対1対応で、1メアドで複数のgitアカを持つことはできないみたいですね。
ということで、gmailアドレスを新規に取ることにします。
アカウント作成時は一旦それでいいんですけど、その後のgit管理の際のuser.nameとuser.email。
都度、アカウントに対応したnameとemailを使うべきなのですけど、、絶対混ざるんですよね。。
どこまで厳密に考えるべきか。
そもそも、nameとemailを完全分離するメリットなんだろう。日頃使いアカのgitが人様に見せるアカのgitと紐付けられて、公開したくないコードや活動が人目につくのを防げることか。
そもそも公開しては「いけない」ものは公開してないし、みられても恥ずかしいってくらいですむものではありますが、、気持ちは悪いな。
prodとstgは、forkの関係性でどうやっても結びつくし、この2つは「気をつけるけど、まぁごちゃまぜになってもいいか」で管理。一方、「日頃使い」とは絶対に紐付かないように厳密管理。
具体的いは、開発用の環境を明確に分けますかね。
幸い開発環境はdockerコンテナでまとめるようにしてますし、別々のコンテナ使うルールを自分の中で徹底すれば大丈夫。。。かな。
まぁ実際にこの方針で運用してアブなさそうなら、別途考えるか。
2. push前の毎回チェック
まず、今回まとめてることをちゃんとやること。
めんどいし、スクリプトにまとめては置くけれど。
それが終わってからの作業色々。
過去コミットの一掃
「人様に見せるアカの開発用アカ」ではストレスを感じないよう、適当にcommit管理していきたい。
でも、「人様に見せるアカ」に引っ越すときは、しょうもない理由でちょこちょこcommitしてたのは恥ずかしいから消したい。
そんなときのための処理。
reset
ある時点で、prodからstgにフォークする。
stgで好き放題コミットして、人様に見せられるところまでまとまったとする。
で、あたかも、stgにフォークした後一発で最新版までの変更を加えたようにしてしまう(途中のしょうもないコミットログを消し去る)という場合。
以下で、『見た目は』消えて見える。でも、.git/objects配下のファイルは残っている。。。
rabaseを使う場合も、残念ながら.git/objectsが消えてくれるというわけではない。。
$ git log
prodからstgにフォークしてきたときのcommitのhashを確認する。今回はXXXXXXとする。
$ git reset XXXXXX
一旦変更したファイルはそのままに、HEADの位置を戻す。
$ git add .
$ git commit -m "Comment"
これで、fork後の1回のcommitで全部の変更を完了したように見せる。
$ git push --force -u origin main
forceは、git上のコミットログも矯正で上書きする際のオプション。
以下はpushに関係するかわからんのだけど、一応メモ。
$ git reflog expire --expire=now --all
過去のコミットログを消す。
git rebase -i XXXXXXの1個前 で、指定以降の分のコミットをsquashする方法もあるのだが、現状違いがわからず。
おそらくちゃんとbranchを使うと大きく違うのだろうけど、、、それは後日考える。
ちなみに以下で見てみると、消したつもりの情報がたくさん見える、、
$ find .git/objects/ -type f |
while read fname; do
echo;
echo;
echo ${fname}; echo ${fname} | sed "s|^.*/\([^/]\+\)/\([^/]\+\)|\1\2|" | xargs git cat-file -t;
echo ${fname}; echo ${fname} | sed "s|^.*/\([^/]\+\)/\([^/]\+\)|\1\2|" | xargs git cat-file -p;
done
特定のファイルを完全抹消したいならfilter-branchでrmするのだが、そういうのではないんだよな。。
現状いい方法が思いつかない。
全く新しくcloneして、最新版のファイル群をまるコピーして、commit、、、で凌ぐしか無いか、、
確実にgitの考え方とずれてると思うのだけれど、いかんともしがたし。。。
commitをあまりホイホイ行わず、ちゃんと意味のある区切りになるまでcommitしない癖をつける、、?
。。。それはそれで不便だと思うな。。
gitに使い慣れてくれば違うのだろうけれど、現状どうにも思いつかないし、、、ほっとこう。。。
Pypiに関すること
1. TestとProd
pypiには、test用のpypiとして、通常のと独立したtest.pypi.orgという環境を持っていて、それぞれ別々にアカウントを登録できる。
prod用gitアカウントを量pypiに紐付けて使うものなのかもだけど、せっかくgitのアカウント自体をprodとstgで2つ分けて作るので、pypiについてもtest.pypi - stg用のgitアカ、pypi - prod用のgitアカ、というように分けて使うようにするか。。
2. pyproject.toml
setup.pyをつくる、ライセンスをおく、テストもちゃんと書く、ソースも当然置く。
ここまでは認識どおりであったのだけれど、pypiのパッケージング手順を読んでいたら意図してなかったファイルがあったので、追加調査。
ビルド時の環境を指定するものらしい。
何も置かなければ、setuptoolsによるビルド。
githubで少々検索してみたけど、ほとんどヒットせず。これ、、、ほんとに使われてるのか、、、?
実はGutHUBのActionsで少々けつまずいたのが、まさにここの関係。setuptools自体が標準導入されてないケースの考慮が厄介だった。
。。痛い目みたんだから、ちゃんとかくか。。
3. パッケージ名の見直し
ここで!?って感はあるんですけれど、まぁ、ここで。。
今回pypiにアップしようとした際に最大の懸案の1つだったのは、「名称の重複」。
それっぽい名前で、シンプルなの使おうとすると、すでに登録されてたりする。
あるいは、今後素晴らしいパッケージを作ってくれた人がいたときに、私が先にいい名前取っちゃってたりすると申し訳がない、、
そもそも一昔前のURLのように、使いそうな名前を投機的に取っておく、みたいな悪質な事ができるんじゃなかろうかなと。。
PEP 541では、名前は先に取ったもの勝ち、と書いてある。
pypiの公開手順のページでは、ひっそりとsetup.cfgの中に記載が。
Be sure to update this with your username, as this ensures you won’t try to upload a package with the same name as one which already exists when you upload the package.
うぇぇ、マジですか、、名前やぽったくなりますよ、、
てか自己顕示欲の塊みたいに見えてヤダなんだけど、、
別の視点で、importのときに名前が長いのめんどくさい、というのもありますが、そっちは、pyyamlみたいに、パッケージ名は長いけどimportのときはシンプルにyamlですます、って方法も取れそうです。
setup.pyのnameは推奨どおり名前をつけて長く。でもsrcの下においてあるパッケージ本体のでディレクトリはスッキリした名前にしておくと、importのときはスッキリした名前の方で使用できるようですね。
。。。想定外の名称衝突の原因になるわけで、むしろそっちのがタチ悪いんじゃないかな、、
ぎりぎりかぶらない線を攻めるにとどめるか。。
4. Bulildからアップまで
まずは、stg環境へ。
上記に記載した細々したチェックを完了してから、、
$ find ./ -name "*.egg" | xargs rm -rf
$ find ./ -name "*.egg-info" | xargs rm -rf
$ find ./ -name "__pycache__" | xargs rm -rf
$ rm -rf ./dict
$ rm -rf ./build
上記色々掃除+dist, build, eggファイルの一掃(念の為)
$ python3 setup.py sdist bdist_wheel
pypiのサイトにはpython3 -m buildを使うよう記載があるのだが、、2021/2/8時点で、build 0.2.0だとエラーがでて動作しない。。
$ python3 -m twine upload --repository testpypi dist/*
pipでtwineとkeyrings.altを導入してから、上記を実施。
keyrings.altを入れてないとtwine実行時にアラートが出るので。詳細影響は未確認、、
先にpypaでトークンを取得しておくと、ユーザ名:__token__、パスワード:トークン値を使い、生のユーザ名とパスワードを使わなくて良くなる。お作法的にそちらのほうが正しいわけですから、従いますか。
$ pip3 install --index-url https://test.pypi.org/simple <Pkg Namecd >
普通にpipしちゃうとprodのpypi.orgから持ってこようとしちゃうので、注意。
上記で動作確認が十分にできたら、prodへ。
prod用にgit履歴をなかったコトにして、ライセンスのメアドを書き換えて。
脳内で使うアカウントをprodモードに切り替えて、、、
$ python3 setup.py sdist bdist_wheel
$ python3 -m twine upload --repository pypi dist/*
#### 5. 自動化
ビルドからアップロードまで、Github Actionsで実行することができる。
https://github.com/marketplace/actions/pypi-publish
↑これアップロード「しか」しないらしいので、buildは別途自分で実施させないといけないらしい。
以下を参考にさせていただいて、全部自分で書いちゃうほうが妥当な気がしてくるな。。
https://blog.youyo.io/posts/publish-packages-to-pypi-with-github-actions/
ただし、これforkして使うときには、workflowが邪魔、、、というかフォークした人が自分のレポジトリにpushした際にActionsが起動してへんてこなことにならないかな、これ。。
自動化するかどうかは、実際にアップして、その後の更新運用を始めてから再度考え直しますか。
## 公開後の話
#### 1. requrementsの更新への追従
importしているパッケージも都度更新されるわけで、余り古いバージョンをしているのは格好が悪い。
また、上記の検討で「最新版で仕様が変わるかもしれないけど、それは公開後運用で考える」と放り投げちゃっているので、やり方を考えないと。。
懸案すべきで思いつくのは2つ。
1つは、パッケージの更新で関数の仕様が変わって、自身のパッケージがちゃんと動かなくなること。
もう1つは、指定しているバージョンが古くなりすぎていて恥ずかしいこと。あるいは、他のパッケージとバージョンが噛み合わない(対象のパッケージが他のパッケージに依存していて、他パッケージがバージョンX以上じゃないと動かないと指定されているのに、私のrequirementsではXより随分古いバージョンを指定しているなど)。
定期的に以下を試していく、くらいかな。。いい自動化は今の所思いつかないです。
一旦時パッケージを導入したら、
$ pip3 list --outdated
$ pip3 -U install <更新があるもの>
$ python3 setup.py test
#### 2. 自身のパッケージの更新方針
prodとstgの使い分けと、gitのコミットログにゴミを載せない、という観点で上記にまとめた内容を淡々と遵守していくことに鳴るのだけれど、、現実的に運用できるか、自動化できるかは、今後アップしてみた後に考えます。
# 最後に
gitへのアップ+pypiへのアップについて、実際にやって見る上での気になってる点は一通り吐き出し、一通り考え方と注意点は整理できた、、と思う。
あとは、実際にアップしてみてからじゃないとわからないですね。
さぁ、アップするぞ!