IBM Cloud の Cloud Foundry (Python) チュートリアルのハマりポイント

## IBM Cloud Cloud Foundry とは
[Could Foundry](https://www.ibm.com/jp-ja/cloud/cloud-foundry) は Azure App Service のようなもので、フルマネージドの環境で自身の書いたコードが実行できる便利なサービスです。


## チュートリアル
[こちらのチュートリアル](https://cloud.ibm.com/docs/runtimes/python?topic=Python-getting_started)が大変参考になります。基本的にこれに従えばオールオッケーですが、一部ハマりポイントがあったので共有したいと思います。

## WSL (Windows Subsystem for Linux)環境でハマる

WSL上でWindows側のディレクトリに `git clone` を実行すると、すべてのファイルがフルパーミッションになります。この状態で`hello.py`を実行すると以下の例外が発生します。

```python
Traceback (most recent call last):
  File "hello.py", line 88, in <module>
    app.run(host='0.0.0.0', port=port, debug=True)
  File "/home/ottylab/.pyenv/versions/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 841, in run
    run_simple(host, port, self, **options)
  File "/home/ottylab/.pyenv/versions/ibm-sample/lib/python3.7/site-packages/werkzeug/serving.py", line 988, in run_simple
    run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
  File "/home/ottylab/.pyenv/versions/ibm-sample/lib/python3.7/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
    sys.exit(reloader.restart_with_reloader())
  File "/home/ottyalb/.pyenv/versions/ibm-sample/lib/python3.7/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
    exit_code = subprocess.call(args, env=new_environ, close_fds=False)
  File "/home/ottylab/.pyenv/versions/3.7.0/lib/python3.7/subprocess.py", line 304, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/home/ottylab/.pyenv/versions/3.7.0/lib/python3.7/subprocess.py", line 756, in __init__
    restore_signals, start_new_session)
  File "/home/ottylab/.pyenv/versions/3.7.0/lib/python3.7/subprocess.py", line 1499, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: '/mnt/c/ottylab/project/ibm-cloud/get-started-python/hello.py'
```

[stackoverflow](https://stackoverflow.com/questions/55271912/flask-cli-throws-oserror-errno-8-exec-format-error-when-run-through-docker)によると、実行権限がついているのに shebang がないとこの例外が発生するようです。記事の通り、`#!/usr/bin/env python3`をつければ動くようになりますが、ここは素直に `/home/[user dir]`にクローンするのが良いのではないかと思います。


## Python 3.7でハマる

Python 3.7環境で [ステップ 6: データベースを使用する](https://cloud.ibm.com/docs/runtimes/python?topic=Python-getting_started#use_database) を実行し `http://localhost:8000/api/visitors` にアクセスすると以下の例外が発生します。

```python
Traceback (most recent call last):
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/ottylab/.pyenv/versions/3.7.0/envs/ibm-sample/lib/python3.7/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/ottylab/get-started-python/hello.py", line 54, in get_visitor
    return jsonify(list(map(lambda doc: doc['name'], db)))
RuntimeError: generator raised StopIteration
```

generator 周りで問題が発生していますが、これはPython 3.7で入った[以下の変更](https://docs.python.org/ja/3/library/exceptions.html#StopIteration)によるものです。

> バージョン 3.7 で変更: PEP 479 が全てのコードでデフォルトで有効化されました: ジェネレータから送出された StopIteration は RuntimeError に変換されます。


例外を発生させているモジュールは `db` のインスタンスを作成している `Cloudant`です。`get-started-python`の`requirement.txt`では `2.4.0` が指定されていますが、これを最新の `2.12.0` にしてインストールしなおすと問題は解決します。

ちなみに、問題解決後に `http://localhost:8000/` にアクセスすると、「お名前を教えてください」の下に「データベースの内容」が表示されるようになります。


[python-cloudant](https://github.com/cloudant/python-cloudant) のどの修正が該当箇所なのかは今後要調査。