nikkie-ftnextの日記

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

Streamlitで環境変数でもstreamlit runの引数でも設定できる裏には何がある? STREAMLIT_BROWSER_GATHER_USAGE_STATSと--browser.gatherUsageStatsをつなぐもの

はじめに

ちょw 俺ww 有名人じゃんwww、nikkieです。

Streamlitの複数の設定方法について、「どう実装しているんだろう」と気になった箇所を読み解きました。
昨日の神勉強会で知った概念、内需ドリブンですね

目次

複数の方法で設定できるStreamlit! では、どう実装されている?

先日、Streamlitは複数通りで設定できることを知りました。

  1. グローバルのtomlファイル
  2. プロジェクトごとのtomlファイル
  3. 環境変数
  4. streamlit runの引数

例えば、使用統計の収集をオプトアウトする設定値は以下の方法で設定できます。

  • 環境変数 STREAMLIT_BROWSER_GATHER_USAGE_STATS=false
  • streamlit runの引数 --browser.gatherUsageStats false

いろいろな設定方法があって便利だな〜と思ったのですが、実装はどうやっているのか気になりました。
環境変数でもコマンドの引数でも(この記事では追いませんがtomlファイルでも)設定できます。
私、気になります! とソースコードを読みに行きました。

今回追うのは環境変数とコマンドの引数が対応する仕組みです

コマンドの引数--browser.gatherUsageStats環境変数STREAMLIT_BROWSER_GATHER_USAGE_STATSが対応する仕組み

streamlit.config.get_config

Streamlitの設定を確認できるget_configから見ていきます1
https://github.com/streamlit/streamlit/blob/1.22.0/lib/streamlit/config.py#L131-L147

config_options = get_config_options()

config全体を取得する関数の呼び出しがあります。

streamlit.config.get_config_options

https://github.com/streamlit/streamlit/blob/1.22.0/lib/streamlit/config.py#L1129-L1204

docstringに「Configuration」のドキュメントと同じ記載があります。

Config option values are sourced from the following locations. Values set in locations further down the list overwrite those set earlier.
1. default values defined in this file
2. the global ~/.streamlit/config.toml file
3. per-project $CWD/.streamlit/config.toml files
4. environment variables such as STREAMLIT_SERVER_PORT
5. command line flags passed to streamlit run

実装は長いので必要なところだけ抜粋します。

グローバルとプロジェクト単位のtomlファイルについて_update_config_with_tomlを呼んだ2後、_update_config_with_sensitive_env_varがあります(ここはドキュメントの記載通りの実装になっていますね!)。

streamlit.config._update_config_with_sensitive_env_var

https://github.com/streamlit/streamlit/blob/1.22.0/lib/streamlit/config.py#L1035-L1046

Update the config system by parsing the environment variable.3

意訳:環境変数をパースし、configシステムを更新する

引数で渡ってくるのはdict[str, ConfigOption]
itemsで繰り返して、

for opt_name, opt_val in config_options.items():
    # 省略
    env_var_value = os.environ.get(opt_val.env_var)

環境変数を読み取っているところがありました!

streamlit.config_option.ConfigOptionenv_var

https://github.com/streamlit/streamlit/blob/1.22.0/lib/streamlit/config_option.py#L303-L309

ここが、コマンドの引数--browser.gatherUsageStats環境変数STREAMLIT_BROWSER_GATHER_USAGE_STATSが対応する仕組みと理解しました!

@property
def env_var(self):
    name = self.key.replace(".", "_")
    return f"STREAMLIT_{to_snake_case(name).upper()}"

ConfigOptionkey属性には"browser.gatherUsageStats"のような"section.optionName"形式の文字列が入ってきます。

(脱線)tomlでは以下のように対応します

[section]
optionName = "awesome"

env_varプロパティの実装ですが、

  1. "section.optionName" -> "section_optionName"と変換
    • 区切りをアンダースコアに変更(環境変数にすることを見越した区切り文字選択!)
  2. to_snake_case関数でキャメルケースに変換"section_option_name"
  3. upperで全部大文字にする。環境変数になってる!!("SECTION_OPTION_NAME"

このあたりの読み解きの確認には、テストコードを覗きました。
https://github.com/streamlit/streamlit/blob/1.22.0/lib/tests/streamlit/config_test.py#L75-L89

終わりに

Streamlitでstreamlit runの引数--browser.gatherUsageStats環境変数STREAMLIT_BROWSER_GATHER_USAGE_STATSが対応する仕組みが気になり、確認しました。

ポイントはConfigOptionオブジェクトだと思います。
これがコマンドの引数と環境変数(そしておそらくはtomlファイルも)を結びつけています!
コマンドの引数と環境変数が対応する仕組みは、コマンドの引数をキャメルケースからスネークケースに変換し、大文字にするという変換ロジックです。
コマンドの引数に対応する環境変数を読み取る機能を実装することで、複数通りの設定をサポートしているのですね〜


  1. こちらでも取り上げましたね
  2. https://github.com/streamlit/streamlit/blob/1.22.0/lib/streamlit/config.py#L1177-L1184
  3. This should only be called from get_config_options.」と続きます