(ソースコードメモ)Pythonのモジュール実行


#動作概要
以下のように、xxxx (例:http.serverやpdb)でモジュールを指定して実行出来る。

```
python -m xxxx yyyy.py
```
上記のコマンドでは、module(モジュール)が直接呼び出されたとき、いずれか(ファイルもしくはディレクトリ)の処理が行われる。

- (ファイル)該当Pythonスクリプトが実行される。具体的には、`__name__`変数が`__main__`となる時の処理が、実行される。
- (ディレクトリ)該当ディレクトリを指定した場合、配下にある`__main__.py`というファイルが、実行される。

これにより、(モジュールとして呼び出している)スクリプトxxxxから(最終的に解析を行う)スクリプトyyyyを呼び出す処理等が容易に出来る。
これは、[PEP338](https://www.python.org/dev/peps/pep-0338/)で定義されておりPythonでは、runpyモジュールで実装されている。

#モジュール実行をサポートしているモジュール例
Python組み込みだと以下のモジュールが代表的なものである。

- http.server (Webサーバ)
- pdb (デバッガ)
- cProfile (プロファイラ)
- unittest (テストフレームワーク)

それ以外だと、以下がある。なお、pytestには、更に似たようなpluginsのロード機能がある (-pオプション)。

- pytest (テストフレームワーク)(上記unittestの機能拡張のようなもの)
- tensorboard(機械学習モニタリングツール)(python -m tensorboard.mainで使う)

#Pythonインタープリターでの変数設定
さて、Pythonインタープリターは、Pythonスクリプトを実行する時に該当スクリプトのグローバル変数、`__name__`等を設定する。直接呼び出されたファイルでは、`__name__`は`__main__`と設定される。設定されているパラメータは、Pythonから組み込み関数[`globals()`](https://docs.python.org/3/library/functions.html#globals)を実行することにより確認できる。なお、グローバル変数を設定する関数はC言語だが[`_run_code`](https://github.com/python/cpython/blob/3.7/Lib/runpy.py#L62)である。


#参考資料
##概要説明資料
- [(Python)runpy — Locating and executing Python modules](https://docs.python.org/3/library/runpy.html#runpy.run_module)(モジュールオプションを受けて実行処理をする関数の説明)
  - [PEP 338 -- Executing modules as scripts](https://www.python.org/dev/peps/pep-0338/)
  - [(Python)1. Command line and environment](https://docs.python.org/3/using/cmdline.html)
  - [(Python)Built-in Functions globals()](https://docs.python.org/3/library/functions.html#globals)(組み込み関数マニュアル)
  - [(Python)`__main__` — Top-level script environment](https://docs.python.org/3/library/__main__.html)　(`__main__`の説明)
- [pytestのプラグイン組み込み](https://docs.pytest.org/en/latest/plugins.html)
  - [pluggy](https://pluggy.readthedocs.io/en/latest/)(pytestのプラグイン管理ライブラリ)

##ソースコード
### Python 3.7のコードより
- [Py_Main](https://github.com/python/cpython/blob/3.7/Modules/main.c#L3044)
  - [pymain_parse_cmdline](https://github.com/python/cpython/blob/3.7/Modules/main.c#L1638)(コマンドラインのパース)
     - [pymain_parse_cmdline_impl](https://github.com/python/cpython/blob/3.7/Modules/main.c#L740)
  - [pymain_run_module](https://github.com/python/cpython/blob/3.7/Modules/main.c#L286)(モジュールの実行)
     - [def `_run_module_as_main`] (https://github.com/python/cpython/blob/3.7/Lib/runpy.py#L167) (runpyモジュール)
         - [`def _run_code(code, run_globals, init_globals=None,
              mod_name=None, mod_spec=None,
              pkg_name=None, script_name=None)`](https://github.com/python/cpython/blob/3.7/Lib/runpy.py#L62)(Pythonスクリプトのグローバル変数設定関数。4番目の引数で`__name__`を`__main__`と設定))
- Pythonに同梱されているモジュール例
  - [http.server Lib/http/server.py `__main__`](https://github.com/python/cpython/blob/3.7/Lib/http/server.py#L1240)(http.serverモジュールの`__main__`)
     - [Lib/_compat_pickle.py](https://github.com/python/cpython/blob/3.7/Lib/_compat_pickle.py#L178)(Python2のSimpleHTTPServerからPython3のhttp.serverへのマッピング)
  - [pdb Lib/pdb.py `__main__`](https://github.com/python/cpython/blob/3.7/Lib/pdb.py#L1726)(pdbモジュールの`__main__`)
     - [class Pdb(bdb.Bdb, cmd.Cmd)](https://github.com/python/cpython/blob/3.7/Lib/pdb.py#L136)(do_xxxxが、pdbのコマンド処理に該当する)
         - [class Bdb](https://github.com/python/cpython/blob/3.7/Lib/bdb.py#L17)(Pythonデバッガの基本モジュール)
             - [class Breakpoint](https://github.com/python/cpython/blob/3.7/Lib/bdb.py#L654)
  - [cProfile Lib/cProfile.py](https://github.com/python/cpython/blob/3.7/Lib/cProfile.py#L184)
     - [cProfilerクラスの親"_lsprof.Profiler"](https://github.com/python/cpython/blob/3.7/Modules/_lsprof.c#L800)(C言語で実装されている。)
         - [PyEval_SetProfile等のCPython内のプロファイル関数](https://docs.python.org/3/c-api/init.html#profiling-and-tracing)等により(時間等の)プロファイルを取得する。 
  - [unittest """Main entry point"""](https://github.com/python/cpython/blob/3.7/Lib/unittest/__main__.py#L1)(ディレクトリを指定したUnittestの例　`__main__.py`から処理が行われる。)
     - [main](https://github.com/python/cpython/blob/3.7/Lib/unittest/main.py#L275)(unittestのメイン)
         - [_do_discovery](https://github.com/python/cpython/blob/3.7/Lib/unittest/main.py#L233)(test*.pyというファイルの検索ルーチン)

### その他のモジュール
- [pytest](https://github.com/pytest-dev/pytest/blob/5.0.0/src/pytest.py) (pytestモジュールの`__main__`)
  - [`_pytest.config.main`](https://github.com/pytest-dev/pytest/blob/4.6.4/src/_pytest/config/__init__.py#L51)
     - [def wrap_session(config, doit)](https://github.com/pytest-dev/pytest/blob/4.6.4/src/_pytest/main.py#L195)(テストスクリプトを呼び出す箇所。実際のエラー出力もここで行う。)
   - [pytest-dev/pluggy](https://github.com/pytest-dev/pluggy)(pytest用のプラグインをキックする仕組み)

## その他
-  [(StackOverflow)What is the Python 3 equivalent of “python -m SimpleHTTPServer”](https://stackoverflow.com/questions/7943751/what-is-the-python-3-equivalent-of-python-m-simplehttpserver)
  - SimpleHTTPServerがあったのは、Python2までである。Python3でも同じ引数は残っているが、http.serverにマップされるだけである。 定義箇所は、上記のhttp.serverのソースコードの項を参照のこと