Flaskアプリを引っ越す

apostrophe で動いている Flask アプリを wplj に引っ越す。

virtualenvとuwsgiのインストール

takatoh@wplj $ pip install virtualenv
プログラム 'pip' はまだインストールされていません。 次のように入力することでインストールできます:
sudo apt install python-pip

あれ、pip がインストールされてなかった。

takatoh@wplj $ sudo apt install python-pip

では、あらためて。

takatoh@wplj $ sudo pip install virtualenv
takatoh@wplj $ sudo pip install uwsgi

以前のエントリを見たら sudo をつけていたので、今回もつけて実行した。

takatoh@wplj $ pip list
adium-theme-ubuntu (0.3.4)
dnspython (1.12.0)
pip (8.1.1)
pycrypto (2.6.1)
setuptools (20.7.0)
unity-lens-photos (1.0)
uWSGI (2.0.14)
virtualenv (15.1.0)
wheel (0.29.0)
You are using pip version 8.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

virtualenv と uWSGI がちゃんとインストールされてる。pip をアップグレードしろみたいなメッセージが出てるけど、これはあとでいいや。

ユーザを作る

Flask アプリを動かす専用のユーザを作る。

takatoh@wplj $ sudo adduser bruschetta
ユーザー bruschetta' を追加しています...
新しいグループ bruschetta' (1001) を追加しています...
新しいユーザー bruschetta' (1001) をグループ bruschetta' に追加しています...
ホームディレクトリ /home/bruschetta' を作成しています...
/etc/skel' からファイルをコピーしています...
新しい UNIX パスワードを入力してください: 
新しい UNIX パスワードを再入力してください: 
passwd: パスワードは正しく更新されました
bruschetta のユーザ情報を変更中
新しい値を入力してください。標準設定値を使うならリターンを押してください
	フルネーム []: 
	部屋番号 []: 
	職場電話番号 []: 
	自宅電話番号 []: 
	その他 []: 
以上で正しいですか? [Y/n] y

sudo する権利をつける。

takatoh@wplj $ sudo gpasswd -a bruschetta sudo
ユーザ bruschetta をグループ sudo に追加

ここで今作ったユーザでログインしなおす。

Flaskアプリの配置

GitHub からクローン。

bruschetta@wplj:~$ git clone https://github.com/takatoh/Bruschetta.git bruschetta
Cloning into 'bruschetta'...
remote: Counting objects: 358, done.
remote: Total 358 (delta 0), reused 0 (delta 0), pack-reused 358
Receiving objects: 100% (358/358), 31.96 KiB | 0 bytes/s, done.
Resolving deltas: 100% (241/241), done.
Checking connectivity... done.

virtualenv を作って必要なライブラリをインストール。

bruschetta@wplj:~/bruschetta$ virtualenv env
New python executable in /home/bruschetta/bruschetta/env/bin/python
Installing setuptools, pip, wheel...done.
bruschetta@wplj:~/bruschetta$ source env/bin/activate
(env) bruschetta@wplj:~/bruschetta$ pip install -r requirements.txt
Collecting Flask (from -r requirements.txt (line 1))
  Downloading Flask-0.12-py2.py3-none-any.whl (82kB)
    100% |████████████████████████████████| 92kB 3.0MB/s 
Collecting Flask-SQLAlchemy (from -r requirements.txt (line 2))
  Downloading Flask_SQLAlchemy-2.2-py2.py3-none-any.whl
Collecting Flask-Script (from -r requirements.txt (line 3))
  Downloading Flask-Script-2.0.5.tar.gz (42kB)
    100% |████████████████████████████████| 51kB 4.0MB/s 
Collecting itsdangerous>=0.21 (from Flask->-r requirements.txt (line 1))
  Downloading itsdangerous-0.24.tar.gz (46kB)
    100% |████████████████████████████████| 51kB 4.6MB/s 
Collecting click>=2.0 (from Flask->-r requirements.txt (line 1))
  Downloading click-6.7-py2.py3-none-any.whl (71kB)
    100% |████████████████████████████████| 71kB 4.4MB/s 
Collecting Werkzeug>=0.7 (from Flask->-r requirements.txt (line 1))
  Downloading Werkzeug-0.11.15-py2.py3-none-any.whl (307kB)
    100% |████████████████████████████████| 317kB 3.0MB/s 
Collecting Jinja2>=2.4 (from Flask->-r requirements.txt (line 1))
  Downloading Jinja2-2.9.5-py2.py3-none-any.whl (340kB)
    100% |████████████████████████████████| 348kB 4.0MB/s 
Collecting SQLAlchemy>=0.8.0 (from Flask-SQLAlchemy->-r requirements.txt (line 2))
  Downloading SQLAlchemy-1.1.5.tar.gz (5.1MB)
    100% |████████████████████████████████| 5.1MB 237kB/s 
Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->Flask->-r requirements.txt (line 1))
  Downloading MarkupSafe-0.23.tar.gz
Building wheels for collected packages: Flask-Script, itsdangerous, SQLAlchemy, MarkupSafe
  Running setup.py bdist_wheel for Flask-Script ... done
  Stored in directory: /home/bruschetta/.cache/pip/wheels/e2/ea/d8/8d114e46cef819f7d9879504a7f9cb2a88a479af2858223d9f
  Running setup.py bdist_wheel for itsdangerous ... done
  Stored in directory: /home/bruschetta/.cache/pip/wheels/fc/a8/66/24d655233c757e178d45dea2de22a04c6d92766abfb741129a
  Running setup.py bdist_wheel for SQLAlchemy ... done
  Stored in directory: /home/bruschetta/.cache/pip/wheels/8d/0a/3b/2109101a4052e58ad64f83661383a6b483a1c383eb09aad6d6
  Running setup.py bdist_wheel for MarkupSafe ... done
  Stored in directory: /home/bruschetta/.cache/pip/wheels/a3/fa/dc/0198eed9ad95489b8a4f45d14dd5d2aee3f8984e46862c5748
Successfully built Flask-Script itsdangerous SQLAlchemy MarkupSafe
Installing collected packages: itsdangerous, click, Werkzeug, MarkupSafe, Jinja2, Flask, SQLAlchemy, Flask-SQLAlchemy, Flask-Script
Successfully installed Flask-0.12 Flask-SQLAlchemy-2.2 Flask-Script-2.0.5 Jinja2-2.9.5 MarkupSafe-0.23 SQLAlchemy-1.1.5 Werkzeug-0.11.15 click-6.7 itsdangerous-0.24

データベースの初期化。

(env) bruschetta@wplj:~/bruschetta$ python manage.py init_db
manage.py:2: ExtDeprecationWarning: Importing flask.ext.script is deprecated, use flask_script instead.
  from flask.ext.script import Manager
/home/bruschetta/bruschetta/bruschetta/__init__.py:2: ExtDeprecationWarning: Importing flask.ext.sqlalchemy is deprecated, use flask_sqlalchemy instead.
  from flask.ext.sqlalchemy import SQLAlchemy

なんか SQLAlchemy がらみでメッセージが出てるな。まあいい、先に進めよう。
起動確認。

(env) bruschetta@wplj:~/bruschetta$ python manage.py runserver
manage.py:2: ExtDeprecationWarning: Importing flask.ext.script is deprecated, use flask_script instead.
  from flask.ext.script import Manager
/home/bruschetta/bruschetta/bruschetta/__init__.py:2: ExtDeprecationWarning: Importing flask.ext.sqlalchemy is deprecated, use flask_sqlalchemy instead.
  from flask.ext.sqlalchemy import SQLAlchemy
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Feb/2017 20:14:23] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Feb/2017 20:14:23] "GET /static/style.css HTTP/1.1" 200 -
127.0.0.1 - - [28/Feb/2017 20:14:23] "GET /favicon.ico HTTP/1.1" 404 -

OK。ブラウザでも確認できた。
ここで virtualenv から抜ける。

(env) bruschetta@wplj:~/bruschetta$ deactivate

uWSGIで起動

uWSGI の設定ファイルを apostrophe からコピーしてくる。

bruschetta@wplj:~/bruschetta$ scp bruschetta@apostrophe:bruschetta/bruschetta.ini .
bruschetta@apostrophe's password: 
bruschetta.ini                                100%  350     0.3KB/s   00:00

内容はこんな感じ。

ディレクトリ構成は一緒だから、このまま行けるはずだ。

bruschetta@wplj:~/bruschetta$ sudo uwsgi bruschetta.ini
[sudo] bruschetta のパスワード: 
[uWSGI] getting INI configuration from bruschetta.ini

OK。今度もブラウザで確認できた。

起動スクリプト

これも以前のスクリプトと同じ。

起動確認。

bruschetta@wplj:~/bruschetta$ sudo service bruschetta start
Failed to start bruschetta.service: Unit bruschetta.service not found.

あれ、ダメだ。bruschetta.service ってなんだ?
ググってみると、/lib/systemd/system/bruschetta.service ファイルを作ってやればいいようだけど、書き方がよくわからない。どうしたもんか……

RubyとPythonをインストール

Ruby

takatoh@wplj $ sudo apt install ruby
takatoh@wplj $ ruby -v
ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]

おお、2.3だ。

Python

takatoh@wplj $ sudo apt install python
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
python はすでに最新バージョン (2.7.11-1) です。
python は手動でインストールしたと設定されました。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 432 個。

あれ、入ってる?

takatoh@wplj $ python -V
Python 2.7.11+

入ってた。

PythonでMD5ダイジェスト値を求める

hashlib を使う。
試しに、MD5 を計算/チェックするスクリプトを書いてみた。

実行例:

takatoh@apostrophe $ python md5.py sample.zip > a.md5
takatoh@apostrophe $ cat a.md5
72f163b717dbe53cd58902713dc10152  sample.zip
takatoh@apostrophe $ python md5.py -c a.md5
sample.zip OK

bottleアプリをuWSGIで動かす

やってみよう!

今回動かすアプリ

単純に、指定されたファイルをダウンロードさせるだけのアプリを書いた。

run 関数が直接 python index.py したとき用の記述で、application = default_app() が uWSGI 用の記述。

下準備

uWSGI で動かす前に、実行用の環境を env という名前で作っておく。

takatoh@apostrophe $ ls
index.py  requirements.txt
takatoh@apostrophe $ virtualenv env
New python executable in env/bin/python
Installing setuptools, pip, wheel...done.
takatoh@apostrophe $ source env/bin/activate
(env)takatoh@apostrophe $ pip install -r requirements.txt
Collecting bottle==0.12.10 (from -r requirements.txt (line 1))
/home/takatoh/w/myapp/env/local/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
  Using cached bottle-0.12.10-py2-none-any.whl
Installing collected packages: bottle
Successfully installed bottle-0.12.10
/home/takatoh/w/myapp/env/local/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
You are using pip version 7.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
(env)takatoh@apostrophe $ deactivate

それから、storage という名前のディレクトリを作って、ファイル(101_ObjectCategories.tar.gz)を入れておく。これをダウンロードしてみようってわけだ。

uWSGIで起動

まずは、コマンドラインから起動してみる。

takatoh@apostrophe $ uwsgi --http :8080 --wsgi-file index.py -H env

ダウンロードできるか、テスト。

takatoh@apostrophe $ wget http://localhost:8080/101_ObjectCategories.tar.gz
--2016-11-24 20:33:35--  http://localhost:8080/101_ObjectCategories.tar.gz
localhost (localhost) をDNSに問いあわせています... 127.0.0.1
localhost (localhost)|127.0.0.1|:8080 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 131740031 (126M) [application/x-tar]
101_ObjectCategories.tar.gz' に保存中

100%[======================================>] 131,740,031 68.1MB/s   時間 1.8s 

2016-11-24 20:33:37 (68.1 MB/s) - 101_ObjectCategories.tar.gz' へ保存完了 [131740031/131740031]

出来た。以前、Flask アプリを動かした時より簡単だな。

設定ファイルで起動

uWSGI 用の設定ファイル。

起動。

takatoh@apostrophe $ uwsgi uwsgi.ini
[uWSGI] getting INI configuration from uwsgi.ini

ダウンロードのテスト。

takatoh@apostrophe $ wget http://localhost:8080/101_ObjectCategories.tar.gz
--2016-11-25 08:35:08--  http://localhost:8080/101_ObjectCategories.tar.gz
localhost (localhost) をDNSに問いあわせています... 127.0.0.1
localhost (localhost)|127.0.0.1|:8080 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 131740031 (126M) [application/x-tar]
101_ObjectCategories.tar.gz' に保存中

100%[======================================>] 131,740,031 28.6MB/s   時間 4.5s 

2016-11-25 08:35:13 (27.8 MB/s) - 101_ObjectCategories.tar.gz' へ保存完了 [131740031/131740031]

OK。うまくいった!

辞書の値によってキーを削除する

例えば、こんな辞書があったとする。

>>> dic = {'Andy': 27, 'Bill': 32, 'Charlie': 24}

この辞書から、値が 30 を超えるキー(つまり ‘Bill’)を削除したい。こうすると:

>>> for k in dic:
...     if dic[k] > 30:
...         del(dic[k])
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

エラーになる(イテレーションの最中に辞書のサイズが変わってるって怒られる)。
でもキーは削除されてる。

>>> dic
{'Charlie': 24, 'Andy': 27}

なんでだかは解らない。
エラーが出ないようにするには items() メソッドを使えばいい。今度は値が 25 を超えるキーを削除してみる。

>>> for k, v in dic.items():
...     if v > 25:
...         del(dic[k])
...
>>> dic
{'Charlie': 24}

無事に消えた。

Pythonの軽量Webフレームワークbottleを使ってみる(2)

テンプレートについて補足。
昨日のスクリプトでは、template 関数の引数に直接テンプレートを文字列として渡していた。短いテンプレートならそれでもいいけど、引数として文字列で渡すには長すぎるのが普通だ。そこで、テンプレートそのものじゃなく、名前で指定できるようになっている。
テンプレートは、スクリプトと同じディレクトリの下に views という名前でディレクトリを作って、その中に入れておく。そうすると bottle がテンプレートを見つけて読み込んでくれる。
次のスクリプトでは info という名前のテンプレートを使っている。

で、テンプレートのほうはこう。

Pythonの軽量Webフレームワークbottleを使ってみる

インストール

pip でインストール。

takatoh@apostrophe $ pip install bottle
Collecting bottle
/usr/local/lib/python2.7/dist-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
  Downloading bottle-0.12.10-py2-none-any.whl (88kB)
    100% |████████████████████████████████| 90kB 3.6MB/s 
Installing collected packages: bottle
Exception:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/pip/basecommand.py", line 211, in main
    status = self.run(options, args)
  File "/usr/local/lib/python2.7/dist-packages/pip/commands/install.py", line 311, in run
    root=options.root_path,
  File "/usr/local/lib/python2.7/dist-packages/pip/req/req_set.py", line 646, in install
    **kwargs
  File "/usr/local/lib/python2.7/dist-packages/pip/req/req_install.py", line 803, in install
    self.move_wheel_files(self.source_dir, root=root)
  File "/usr/local/lib/python2.7/dist-packages/pip/req/req_install.py", line 998, in move_wheel_files
    isolated=self.isolated,
  File "/usr/local/lib/python2.7/dist-packages/pip/wheel.py", line 339, in move_wheel_files
    clobber(source, lib_dir, True)
  File "/usr/local/lib/python2.7/dist-packages/pip/wheel.py", line 317, in clobber
    shutil.copyfile(srcfile, destfile)
  File "/usr/lib/python2.7/shutil.py", line 83, in copyfile
    with open(dst, 'wb') as fdst:
IOError: [Errno 13] Permission denied: '/usr/local/lib/python2.7/dist-packages/bottle.py'
You are using pip version 7.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

って、えー、なんかいきなりエラーが出るじゃん。pip をアップグレードしろ、といってるみたいなので、そうしてみる。

takatoh@apostrophe $ pip install --upgrade pip
/usr/local/lib/python2.7/dist-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
Collecting pip
  Downloading pip-9.0.1-py2.py3-none-any.whl (1.3MB)
    100% |████████████████████████████████| 1.3MB 451kB/s 
Installing collected packages: pip
  Found existing installation: pip 7.1.2
    Uninstalling pip-7.1.2:
Exception:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/pip/basecommand.py", line 211, in main
    status = self.run(options, args)
  File "/usr/local/lib/python2.7/dist-packages/pip/commands/install.py", line 311, in run
    root=options.root_path,
  File "/usr/local/lib/python2.7/dist-packages/pip/req/req_set.py", line 640, in install
    requirement.uninstall(auto_confirm=True)
  File "/usr/local/lib/python2.7/dist-packages/pip/req/req_install.py", line 716, in uninstall
    paths_to_remove.remove(auto_confirm)
  File "/usr/local/lib/python2.7/dist-packages/pip/req/req_uninstall.py", line 125, in remove
    renames(path, new_path)
  File "/usr/local/lib/python2.7/dist-packages/pip/utils/__init__.py", line 315, in renames
    shutil.move(old, new)
  File "/usr/lib/python2.7/shutil.py", line 303, in move
    os.unlink(src)
OSError: [Errno 13] Permission denied: '/usr/bin/pip'
You are using pip version 7.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

ダメじゃん。同じようなエラーが出る。
ググってみると↓このページを見つけた。

 cf. bottle超初歩入門 – Qiita

なんか、pip でインストールしようとするのが間違いみたいなことが書いてある。bottle はファイル1つでできているので、それをダウンロードして、スクリプトと同じディレクトリに置くのが簡単らしい。

 https://raw.githubusercontent.com/bottlepy/bottle/master/bottle.py

takatoh@apostrophe $ wget https://raw.githubusercontent.com/bottlepy/bottle/master/bottle.py

これで bottle.py がダウンロードできた。なんか釈然としないけど今のところはよしとする。

Hello, world!

まず初めは、定石通り Hello, world。

bottle から routerun をインポート。route デコレータでルーティングを行い、run 関数でサーバを走らせる、ってことのようだ。
これで http://localhost:8080/hello にブラウザでアクセスすると、ちゃんと「Hello, world!」と表示された。

パス中にパラメータ

URL のパス中にパラメータを入れることができる。下の < > で囲んであるところがそれ。

例えば、http://localhost:8080/hello/Andy にアクセスすると「Hello, Andy!」と返ってくる。

リダイレクト

redirect 関数を使う。

ついでに、run 関数の引数に reloader=True を指定した。これによって、サーバを起動したままでもファイルを書き換えると自動的にリロードしてくれるようになる。

Not found

abort 関数。ステータスコードとメッセージを指定できる。

この例では、http://localhost:8080/ にアクセスすると /hello にリダイレクトされて、Not found になる。

リファラと接続元IPアドレス

request オブジェクトからリクエストの情報が取れる。リファラは request.headers.get('Referer')

一方、IPアドレスは request.environ.get('REMOTE_ADDR')

テンプレート

bottle から template をインポートすることで、簡易なテンプレートエンジンが使えるようになる。

静的ファイル

static_file 関数を使う。

引数に download=True を指定すると、ブラウザで開くのではなくダウンロードするようになる。

ふう、今日のところはここまで。

[追記]

Windows 10 では、pip で普通にインストールできた。なんでだ?

[追記2]

sudo をつけたら、pip のアップグレードも bottle のインストールもうまくいった。

clickで–versionオプションを実装する

以前使った Python の click モジュールだけど、コマンドやオプションを定義すると自動で --help オプションを作ってくれる。例えばこんなスクリプトがあったとすると:

こんな感じでヘルプメッセージを生成してくれる。

takatoh@nightschool $ python hello.py --help
Usage: hello.py [OPTIONS] [NAME]

Options:
  -t, --times INTEGER  Repeat.
  -m, --morning        In morning.
  --help               Show this message and exit.

だけど、--version オプションまでは作ってくれない。まあ、当たり前だ。
で、どうするかというと @click.version_option デコレータを使う。

これで --version オプションが使えるようになる。

takatoh@nightschool $ python hello_version.py --version
hello_version.py, version 0.1.0

ちょっと表示が冗長なので、もう少しシンプルにしてみる。デコレータの引数でメッセージのフォーマットを渡してやる。

takatoh@nightschool $ python hello_version2.py --version
hello_version2.py v0.1.0

ちょっとだけシンプルになった。

参考ページ:
 cf. API – click

pyenvを使って最新のPythonをインストールする

pyenvとは

複数のバージョンの Python を切り替えて使えるようにするもの。Ruby の rvm とか rbenv みたいなもの。

pyenvのインストール

インストールというか、GitHub からクローンしてくる。ここではホームディレクトリ下の .pyenv にクローン。

takatoh@nightschool $ git clone git://github.com/yyuu/pyenv.git .pyenv
Cloning into '.pyenv'...
remote: Counting objects: 11571, done.
remote: Compressing objects: 100% (158/158), done.
remote: Total 11571 (delta 107), reused 0 (delta 0), pack-reused 11391
Receiving objects: 100% (11571/11571), 2.05 MiB | 399.00 KiB/s, done.
Resolving deltas: 100% (8114/8114), done.
Checking connectivity... done.

続いて .bashrc に以下を追記。

シェルを起動し直すと pyenv コマンドが使えるようになる。

takatoh@nightschool $ pyenv
pyenv 20151210-1-ge66dcf2
Usage: pyenv <command> [<args>]

Some useful pyenv commands are:
   commands    List all available pyenv commands
   local       Set or show the local application-specific Python version
   global      Set or show the global Python version
   shell       Set or show the shell-specific Python version
   install     Install a Python version using python-build
   uninstall   Uninstall a specific Python version
   rehash      Rehash pyenv shims (run this after installing executables)
   version     Show the current Python version and its origin
   versions    List all Python versions available to pyenv
   which       Display the full path to an executable
   whence      List all Python versions that contain the given executable

See `pyenv help ' for information on a specific command.
For full documentation, see: https://github.com/yyuu/pyenv#readme

Python 2.7.11をインストール

特定のバージョンをインストールするには pyenv install コマンド。

takatoh@nightschool $ pyenv install 2.7.11
Downloading Python-2.7.11.tgz...
-> https://www.python.org/ftp/python/2.7.11/Python-2.7.11.tgz
Installing Python-2.7.11...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
Installed Python-2.7.11 to /home/takatoh/.pyenv/versions/2.7.11

あれ、なんか WARNING が出た。インストール自体はできてるようだけど……bzip2 が足りないようだ。このページを参考に bzip2 をインストール。

takatoh@nightschool $ sudo apt-get install -y bzip2
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
bzip2 はすでに最新版です。
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  ax25-node firefox-locale-en libax25 linux-headers-3.13.0-34
  linux-headers-3.13.0-34-generic linux-image-3.13.0-34-generic
  linux-image-extra-3.13.0-34-generic openbsd-inetd
これを削除するには 'apt-get autoremove' を利用してください。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 21 個。

インストールされてるじゃん。なんで WARNING が出たんだ?
まあいい、このまま進めよう。

Python 3.5.1をインストール

Python3 系の最新バージョンをインストール。

takatoh@nightschool $ pyenv install 3.5.1
Downloading Python-3.5.1.tgz...
-> https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tgz
Installing Python-3.5.1...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
Installed Python-3.5.1 to /home/takatoh/.pyenv/versions/3.5.1

shimのリフレッシュ

shim がなんだかわからないけど、参考にしたページに書いてあったのでやっておく。

takatoh@nightschool $ pyenv rehash

Pythonのバージョンの切り替え

ここまでの作業で、複数のバージョンがインストールできた。利用可能なバージョンは pyenv versions コマンドで確認できる。

takatoh@nightschool $ pyenv versions
* system (set by /home/takatoh/.pyenv/version)
  2.7.11
  3.5.1
takatoh@nightschool $ python -V
Python 2.7.6

今はシステム標準の 2.7.6。これを 3.5.1 に切り替えるには次のようにする。

takatoh@nightschool $ pyenv global 3.5.1
takatoh@nightschool $ pyenv versions
  system
  2.7.11
* 3.5.1 (set by /home/takatoh/.pyenv/version)

バージョンの切り替えには、もうひとつ pyenv local コマンドもある。どう違うのかよくわからない。

ともかく、これでバージョンを切り替えて使えるようになった。

[追記]

参考ページ
 cf. Macでpyenv+virtualenv – Qiita

Pythonでは空文字列は偽

空文字列は偽で、それ以外の文字列は真と評価される。忘れてたよ。
せっかくなので確認しておこう。

  • 空文字列(””)は偽、それ以外は真
  • 数値の 0 は偽、それ以外は真
  • 空の配列は偽、それ以外は真
  • 空の辞書は偽、それ以外は真
  • 空のタプルは偽、それ以外は真

これ以外では、True は真、False と None は偽。

確認してみよう。

>>> def true_or_false(obj):
...     if obj:
...         return True
...     else:
...         return False
... 
>>> true_or_false("")
False
>>> true_or_false("a")
True
>>> true_or_false(0)
False
>>> true_or_false(-1)
True
>>> true_or_false([])
False
>>> true_or_false([1])
True
>>> true_or_false({})
False
>>> true_or_false({'a':'andy'})
True
>>> true_or_false(())
False
>>> true_or_false((1,))
True