Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OSSを読む python-certifi-win32 編

elda27
December 02, 2021
350

OSSを読む python-certifi-win32 編

Licensed under the CC BY-SA 4.0

まとめ
・Python の初期化時にソースコードを実行したい場合は以下の方法がある
 ・.pthファイルを使ってモンキーパッチを行う
  ・site.main関数(※先にsite.mainを呼び出すラッパーが望ましい)
   ⇒site.mainの実行前はsys.pathにsite-packagesのモジュールが使用不可
  ・execsitecustomize関数
  ・execusercustomize関数
 ・sitecustomizeモジュールを作る
 ・usercustomizeモジュールを作る

elda27

December 02, 2021
Tweet

Transcript

  1. 自己紹介 できること C++, CUDA, Python, Typescript/React お仕事 生産技術 Machine Learning

    生息地 Twitter: https://twitter.com/elda277 Blog: https://elda27.hatenablog.com/ Licensed under CC BY-SA 4.0 2
  2. 企画の趣旨 OSS を読めと言う人は多いが、実際読んだ経験とか記録は少ない 私も読むと良いよとよく言う 1 人だけど自分で読んだ記録はつけたことない 多分、マニアック過ぎて読者層が限定されすぎるからみんな書きたくない (Impression 低そう) 私自身、最近

    Output する気力が無くてとりあえずやってみようと思った ちなみにスライドにしたのはブログ記事として書くだけの文字数を書くのが辛かった から 実際作ってみて分かったけどスライドもしんどい Licensed under CC BY-SA 4.0 5
  3. 今回のネタの前置き(無関係の話が 2 ページ続きます) poetry が proxy 環境下で使えなくて泣いた(SSLError が出る) poetry はモダンなパッケージ管理ツールで関連ツールとしては

    pipenv や pyflow な どがある npm に対する yarn , npx などが相当 poetry 内部でエラーが発生する原因 requests ライブラリを使って pypi からパッケージ情報を fetch この時 proxy の証明書を検証するが、システムに事前登録している SSL 証明書が自動 で参照されない 内部で使用しているライブラリは requests Licensed under CC BY-SA 4.0 6
  4. Python における SSL 証明書の読み出し@ requests Python で HTTP 通信を行う場合に最も使われるライブラリ Requests:

    HTTP for Humans™ らしい 凄い簡単に書ける 検証に使用する証明書は以下の 3 種類から選択 デフォルトで検証に使用する SSL 証明書は certifi モジュールに埋め込まれたものを 使用 certifi は Mozilla がキュレートした証明書を提供するライブラリ REQUESTS_CA_BUNDLE 環境変数 CURL_CA_BUNDLE 環境変数 Licensed under CC BY-SA 4.0 7
  5. Windows でシステム証明書を使う方法 python-certifi-win32 をインストールするだけ 実装を見ても中身は wrapt を使っているだけ? wrapt.when_imported は import

    と同時にモジュールに対して mokey patch を行うデ コレータ 例えば以下の例では import certifi と同時に certifi モジュールが apply_patches の 引数に与えられる 3 import wrapt ... 14 @wrapt.when_imported('certifi') 15 def apply_patches(certifi): 気になっていること どうやって自動で適用しているのか Licensed under CC BY-SA 4.0 8
  6. インタプリタ起動と同時に自動実行する仕組み@ python-certifi- win32 1. Python の初期化時に読み出される pth ファイルから certifi_win32.bootstrap を

    実行 2. execsitecustomize と execusercustomize をラップ@ certifi_win32.bootstrap 3. Python の初期化時に読み出される site.main 内で execsitecustomize か execusercustomize が呼び出される 4. @wrapt.when_imported でラップされた関数が含まれるモジュールを import してモ ンキーパッチを仕込む python-certifi-win32 であれば certifi.where (SSL 証明書が埋め込みファイルの場 所を返す関数)を certifi_win32.wincerts.where() に置き換え Licensed under CC BY-SA 4.0 11
  7. 1. Python の初期化時に読み出される pth ファイルから certifi_win32.bootstrap を実行 pth ファイルとは パス設定ファイル

    sys.path に追加するパスを 1 行ごとに列挙する 1 行だけ Python のコードを含めることができる 例) Embeddable Python の中にある pythonXXX._pth ファイル # 以下2ファイル/ディレクトリが sys.path に追加される python310.zip # ZIPファイルに格納されたパッケージ . # カレントディレクトリ # コメントアウトするとsite-packagesの中にあるライブラリが使えるようになる #import site Licensed under CC BY-SA 4.0 12
  8. 2. execsitecustomize と execusercustomize をラップ @ certifi_win32.bootstrap certifi_win32/bootstrap:#L51 オリジナルの関数をラップしている site.execsitecustomize

    と site.execusercustomize は site.main で呼び出される 初期化関数 42 def _execusercustomize_wrapper(wrapped): 43 def _execusercustomize(*args, **kwargs): 44 try: 45 return wrapped(*args, **kwargs) 46 finally: 47 _register_bootstrap_functions() # モンキーパッチする関数 48 return _execusercustomize ... 52 def bootstrap(): ... # 基本的に2つの関数で同じ処理をしている 69 site.execsitecustomize = _execsitecustomize_wrapper(site.execsitecustomize) 70 site.execusercustomize = _execusercustomize_wrapper(site.execusercustomize) Licensed under CC BY-SA 4.0 13
  9. site モジュールについて モジュールを import すると site.main が呼び出される site.main ではいくつかの初期化処理を行っている Ctrl+D

    , Ctrl+Z などのショートカットキーの登録 sitecustomize (システム管理者向け)と usercustomize (ユーザ向け)のモジュールを作 成することで python 起動時の初期化処理が可能 etc 517 def execsitecustomize(): # usercustomizeも同一設計 518 """Run custom site specific code, if available.""" 519 try: 520 try: 521 import sitecustomize # ユーザがモジュールを作ることを想定している 522 except ImportError as exc: # sitecustomizeモジュールが無い場合例外を握りつぶす 523 if exc.name == 'sitecustomize': 524 pass Licensed under CC BY-SA 4.0 14
  10. 3. Python の初期化時に読み出される site.main 内で execsitecustomize か execusercustomize が呼び出される site

    モジュールは自動で import される python -v で確認すると最後から 2 番目に import されている ちなみに最後は atexit 両関数をラップしていることから _register_bootstrap_functions() が site.main で呼ばれ る 今回は両関数をラップしているが個人的には execsitecustomize だけで良い気がする 557 def main(): ... 582 execsitecustomize() 583 if ENABLE_USER_SITE: 584 execusercustomize() Licensed under CC BY-SA 4.0 15
  11. 4. @wrapt.when_imported でラップされた関数が含まれるモジュールを import してモ ンキーパッチを仕込む 非常にシンプル 14 @wrapt.when_imported('certifi') 15

    def apply_patches(certifi): 16 # Keep local copy of original certifi.where() function 17 global certifi_where 18 certifi_where = certifi.where # マナーとしてオリジナルの関数は残しておく 19 import certifi_win32.wincerts 20 certifi_win32.wincerts.CERTIFI_PEM = certifi.where() 21 22 # Wrap the certify.where function 23 wrapt.wrap_function_wrapper(certifi, 'where', wrap_where) # 関数を置き換える 24 25 from certifi_win32.wincerts import generate_pem, verify_combined_pem 26 if not verify_combined_pem(): # PEM形式のSSL証明書証明書が所定の場所になければ生成する 27 generate_pem() Licensed under CC BY-SA 4.0 16
  12. まとめ Python の初期化時にソースコードを実行したい場合は以下の方法がある .pth ファイルを使ってモンキーパッチを行う site.main 関数(※先に site.main を呼び出すラッパーが望ましい) ⇒

    site.main の実行前は sys.path に site-packages のモジュールが使用不可 execsitecustomize 関数 execusercustomize 関数 sitecustomize モジュールを作る usercustomize モジュールを作る Licensed under CC BY-SA 4.0 17
  13. sitecustomize と usercustomize の使い分け sitecustomize はシステム管理者向け usercustomize はユーザ向け 以下の場合実行されない site.ENABLE_USER_SITE

    を False or None にする False はユーザ側からの設定による None の場合はセキュリティ上の理由 or 管理者からの設定による PYTHONNOUSERSITE 環境変数が設定されている python -S で Python を起動した場合 Licensed under CC BY-SA 4.0 19
  14. .pth ファイルの導入方法 <モジュール名>.pth として OS 毎に異なる場所に配置する 大体 site-packages の中に入れておけば問題ない(諸説あり) 通常は

    Python の setup の過程で配置する setuptools を使う場合は data_files に指定してインストールする Licensed under CC BY-SA 4.0 20