Jupyter with Spark

参考

メモ

よく忘れると思われる、Jupyterをクライアントとしての起動方法をメモ。

Sparkのドキュメント(Environment Variables) の記載の通り、環境変数PYSPARK_DRIVER_PYTHONを使い、 ドライバが用いるPythonを指定する。 GitHub上のpysparkの実装#27 の通り、環境変数PYSPARK_DRIVER_PYTHON_OPTSを使い、 オプションを指定する。

1
PYSPARK_DRIVER_PYTHON=jupyter PYSPARK_DRIVER_PYTHON_OPTS='notebook' ~/Spark/default/bin/pyspark

ちなみに、ガイドにも一応記載されている。

https://github.com/apache/spark/blob/9ccae0c9e7d1a0a704e8cd7574ba508419e05e30/docs/rdd-programming-guide.md#using-the-shell

共有

気になるカンファレンスのメモ2019年版(WIP)

ちゃんとしたまとめは後で実施するつもり。

まとめサイト

HPC Japan

http://www.hpcwire.jp/events

List of Machine Learning / Deep Learning conferences in 2019

https://tryolabs.com/blog/machine-learning-deep-learning-conferences/

The 16 AI and ML conferences you should attend in 2019

https://www.hpe.com/us/en/insights/articles/the-16-ai-and-ml-conferences-you-should-attend-in-2019-1811.html

IEEE関連

IEEE Congress 2019

http://conferences.computer.org/bigdatacongress/2019/

JULY 8-13, 2019, MILAN, ITALY

2019 International Congress on Big Data (BigData Congress 2019) aims to provide an international forum that formally explores various business insights of all kinds of value-added “services.” Big Data is a key enabler of exploring business insights and economics of services.

The 6th IEEE International Conference on Big Data and Smart Computing

February 27th - March 2nd, 2019 Kyoto, JAPAN

http://www.bigcomputing.org/

IEEE 2019 Summit On Future Technology For Smart Cities

April 6, 2019

San Francisco East Bay, California, USA

http://www.big-dataservice.net/html/summit.html

The IEEE International Conference on Cloud Engineering (IC2E)

June 24-27, 2019, Prague, Czech Republic

http://conferences.computer.org/IC2E/2019/index.htm http://www.hpcwire.jp/event/international-conference-on-cloud-engineering-ic2e-2019

The 5th IEEE International Conference on Cloud and Big Data Computing (CBDCom 2019)

August 5-8 2019, Fukuoka, Japan

http://cyber-science.org/2019/cbdcom/

USENIX

2019 USENIX Conference on Operational Machine Learning

MAY 20, 2019 SANTA CLARA, CA, USA

https://www.usenix.org/conference/opml19

2019 USENIX Annual Technical Conference

JULY 10–12, 2019 RENTON, WA, USA

https://www.usenix.org/conference/atc19

2019 USENIX Conference on Operational Machine Learning

MAY 20, 2019 SANTA CLARA, CA, USA Papers and talk proposals due Wednesday, February 13, 2019

https://www.usenix.org/conference/opml19

O'Reilly

Strata

Strata San Francisco 2019

https://conferences.oreilly.com/strata/strata-ca

March 25-28, 2019 San Francisco, CA

Strata London 2019

https://conferences.oreilly.com/strata/strata-eu

29 April–2 May 2019 London, UK

Strata New York 2019

https://conferences.oreilly.com/strata/strata-ny

Sep 23-26, 2019 New York, NY

AI Conference

https://conferences.oreilly.com/artificial-intelligence

AI Conference New York 2019

April 15-18, 2019 New York, NY

AI Conference San Jose 2019

Sep 9-12, 2019 San Jose, CA

VLDB

VLDB 2019

http://vldb.org/2019/

Los Angeles, California - August 26-30, 2019

情報処理学会

https://www.ipsj.or.jp/kenkyukai/sig-plan2018.html

電子情報通信学会

https://www.ieice.org/ken/program/index.php

IBISML

https://www.ieice.org/ken/form/index.php?tgs_regid=552bd5f74c86aa9e100ee3878422e7760e89f6c41f180eebb9271daee1030b58&cmd=info&lang=

LOIS

2019年3月7日(木) - 3月8日(金) 宮古島市中央公民館 視聴覚室 ライフログ活用技術、オフィスインフォメーションシステム、ライフインテリジェンス、および一般

SC

開催日 2019-03-15 - 2019-03-15 会場 国立情報学研究所 発表申込締切日 2019-01-07 議題 「サービスと機械学習」および一般

機械学習工学研究会 ★重要 と共催

機械学習工学研究会(MLSE)

https://mlxse.connpass.com/

その他

SysML 2019

March 31 - April 2, 2019 Stanford, CA

(Registration opens: January 16, 2019)

https://www.sysml.cc/

AI for Government Summit

https://www.re-work.co/events/ai-for-government-summit-canada-2018

Toronto 25 - 26 OCTOBER 2018

MLCONF NEW YORK

https://mlconf.com/events/mlconf-new-york-2019/

March 29, 2019

AI World Conference & Expo

https://aiworld.com/

October 23-25, 2019 Boston, MA

Global Artificial Intelligence Conference

http://www.globalbigdataconference.com/

January 6-11, 2019, Santa Clara, CA;

Applied Artificial Intelligence Conference

https://bootstraplabs.com/artificial-intelligence/applied-artificial-intelligence-conference-2019/

April 18, 2019

AI Toronto/Big Data Toronto

https://ai-toronto.com/

June 12-13, 2019, Toronto

共有

WSL向けのターミナルツール

参考

Hyper

ウェブ界隈の技術を活用したターミナル。 Hyper からダウンロードできる。

インストールすると %USERPROFILE%\.hyper.js に設定ファイルが作成される。 デフォルトはcmd.exeが起動されるようになっているので、WSLを使うように変更する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ diff -u /mnt/c/Users/dobachi/.hyper.js{.2018010101,}
--- /mnt/c/Users/dobachi/.hyper.js.2018010101 2019-01-01 23:26:47.691869000 +0900
+++ /mnt/c/Users/dobachi/.hyper.js 2019-01-01 23:28:25.273185100 +0900
@@ -9,7 +9,7 @@
updateChannel: 'stable',

// default font size in pixels for all tabs
- fontSize: 12,
+ fontSize: 15,

// font family with optional fallbacks
fontFamily: 'Menlo, "DejaVu Sans Mono", Consolas, "Lucida Console", monospace',
@@ -107,7 +107,7 @@

// for setting shell arguments (i.e. for using interactive shellArgs: `['-i']`)
// by default `['--login']` will be used
- shellArgs: ['--login'],
+ shellArgs: ['/C', 'wsl'],

// for environment variables
env: {},

ConEmu

ConEmu からダウンロードできる。 ただし、手元のGPD Pocket上のWSLで使用した時には、ctrl + lで画面クリアするときに 意図と異なる動作をした。

cmder

cmder からダウンロードできる。 ただし、手元のGPD Pocket上のWSLで使用した時には、ctrl + lで画面クリアするときに 意図と異なる動作をした。

共有

Ubuntu上のgvimでフォントが重なる現象

参考

メモ

現象についての議論 の通り、~/.vimrcに以下を追記して回避した。

1
set ambiwidth=double
共有

X Window on wsl for Ubuntu

参考

メモ

Windows側

一通りの流れが説明されたブログ に記載の通り試した。 VcXsrvのダウンロードからダウンロードしたパッケージをインストールする。

なお、インストールすると「XLaunch」がスタートメニューに追加される。 これを都度起動することになるが、スタートアップメニューにショートカットを登録し、 自動起動するようにした。 ( Xサーバーを自動起動しよう! を参考にする)

WSL側

最低限のインストール

関連パッケージのインストール

1
$ sudo apt install git build-essential libssl-dev libreadline-dev zlib1g-dev x11-apps x11-utils x11-xserver-utils libsqlite3-dev nodejs fonts-ipafont libxml2-dev libxslt1-dev

~/.bashrcに環境変数DISPLAYの値を追加

1
2
3
4
5
6
7
8
--- /home/dobachi/.bashrc.2018123001    2018-12-30 23:21:48.626055900 +0900
+++ /home/dobachi/.bashrc 2018-12-30 23:20:26.333894000 +0900
@@ -115,3 +115,5 @@
. /etc/bash_completion
fi
fi
+
+export DISPLAY=localhost:0.0

日本語関連

上記手順だけでは日本語入力環境が整わないので、 WSLを使ってWindowsでmikutterを動かすお前らのWSLはそれじゃダメだ を参考に日本語環境を構築する。 まず、WSLを使ってWindowsでmikutterを動かす のとおり、uim-anthyをインストールし、 お前らのWSLはそれじゃダメだ のとおり、~/.uimを設定する。 結局は、お前らのWSLはそれじゃダメだのとおりで良さそうではある。

1
2
3
4
5
6
7
8
9
10
11
$ sudo apt install language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
$ sudo apt install -y uim uim-xim uim-fep uim-anthy dbus-x11
$ cat << EOF > ~/.uim
(define default-im-name 'anthy)
(define-key generic-on-key? '("<Control> "))
(define-key generic-off-key? '("<Control> "))
EOF
$ cat << EOF >> ~/.profile
export GTK_IM_MODULE=uim
EOF

例:GUI vimのインストール

使いたいツールをインストール。

$ sudo apt install vim-gui-common

(snip)

$ gvim
共有

GPD PocketでBluetoothトラックボールを使うと途中で使用できなくなる現象

参考

当たった症状

Digio2のBluetoothトラックボールを使っていたところ、唐突に使用できなくなる現象にあたった。 そのとき、Windowsの設定画面「Bluetoothとその他のデバイス」を開いたところ、 当該トラックボールは「接続済み」と表示されていた。 デバイスの削除と再度追加、ドライバの更新(結局最新版だった)を試みるも現象は収まらなかった。

対処

関連情報を含むブログ記事 で記載の通り、デバイスマネージャから節電関係の機能を オフにすることで現象は解消したように見える。 おおむね上記ブログのとおりだが、一部デバイス名に差分があったので、 手元で試した方法を記載する。

  • Windowsのランチャーからデバイスマネージャを開く
  • 「ヒューマン インターフェイス デバイス」-> 「Bluetooth HID デバイス」のプロパティを開く。
    • 「電源の管理」を開き、「電力の節電のために…(省略)」のチェックボックスを外す
    • なお、手元の環境では当該デバイスは2件表示されたので両方とも対応した
  • おなじくデバイスマネージャ上で「bluetooth」->「Bluetooth 無線」のプロパティを開く。
    • 「電源の管理」を開き、「電力の節電のために…(省略)」のチェックボックスを外す

備考:ブログとの差分

なお、関連情報を含むブログ記事では、「Bluetooth HID デバイス」のところが 「Bluetooth 低エネルギーGTT 対応 HID デバイス」となっていたようだ。

共有

tmuxでctrl + lを押したときに改行の挙動がおかしくなる現象

参考

メモ

tmux-1419 に記載の通り、~/.tmux.confに以下のように記載すると、 強制的に改行されるようになるようだ。

1
set -as terminal-overrides ',*:indn@'
共有

Basic of SQLAlchemy

参考

簡単な動作確認

エンジンの定義。(今回はSQLiteのインメモリモードを使用)

1
2
from sqlalchemy import create_engine
engine = create_engine('sqlite:///:memory:', echo=True)

テーブルの作成。今回は2種類のテーブルを作成。 ユーザのIDをプライマリキーとして使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
metadata = MetaData()
users = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
Column('fullname', String),
)

addresses = Table('addresses', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', None, ForeignKey('users.id')),
Column('email_address', String, nullable=False)
)

実際にSQLite内でテーブルを定義する。このとき、テーブルの存在を確認するので複数回実行してもよい。(べき等である)

1
metadata.create_all(engine)

挿入のクエリ

まずは空のクエリを定義。

1
ins = users.insert()

strを使うと、SQLを確認できる。

1
2
3
str(ins)
--
'INSERT INTO users (id, name, fullname) VALUES (:id, :name, :fullname)'

今度は値を入れてみる。

1
2
3
4
ins = users.insert().values(name='jack', fullname='Jack Jones')
str(ins)
--
'INSERT INTO users (name, fullname) VALUES (:name, :fullname)'

接続の取得と実行

接続の取得

1
conn = engine.connect()

実行

1
2
3
4
5
result = conn.execute(ins)
--
2018-12-24 14:08:34,031 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname) VALUES (?, ?)
2018-12-24 14:08:34,031 INFO sqlalchemy.engine.base.Engine ('jack', 'Jack Jones')
2018-12-24 14:08:34,032 INFO sqlalchemy.engine.base.Engine COMMIT

挿入されたレコードのプライマリキーの確認。

1
2
3
>>> result.inserted_primary_key
--
[1]

複数ステートメントの実行

先の例と同じ1個ずつ挿入する場合。

1
2
3
4
5
6
7
ins = users.insert()
conn.execute(ins, id=2, name='wendy', fullname='Wendy Williams')
--
2018-12-24 14:12:55,688 INFO sqlalchemy.engine.base.Engine INSERT INTO users (id, name, fullname) VALUES (?, ?, ?)
2018-12-24 14:12:55,688 INFO sqlalchemy.engine.base.Engine (2, 'wendy', 'Wendy Williams')
2018-12-24 14:12:55,688 INFO sqlalchemy.engine.base.Engine COMMIT
<sqlalchemy.engine.result.ResultProxy object at 0x7f63c8ca7940>

複数ステートメントを一度に実行する場合。

1
2
3
4
5
6
7
8
9
10
11
conn.execute(addresses.insert(), [
{'user_id': 1, 'email_address' : 'jack@yahoo.com'},
{'user_id': 1, 'email_address' : 'jack@msn.com'},
{'user_id': 2, 'email_address' : 'www@www.org'},
{'user_id': 2, 'email_address' : 'wendy@aol.com'},
])
--
2018-12-24 14:13:42,077 INFO sqlalchemy.engine.base.Engine INSERT INTO addresses (user_id, email_address) VALUES (?, ?)
2018-12-24 14:13:42,078 INFO sqlalchemy.engine.base.Engine ((1, 'jack@yahoo.com'), (1, 'jack@msn.com'), (2, 'www@www.org'), (2, 'wendy@aol.com'))
2018-12-24 14:13:42,078 INFO sqlalchemy.engine.base.Engine COMMIT
<sqlalchemy.engine.result.ResultProxy object at 0x7f63c8ca7c18>

SELECT

まずはクエリを実行。

1
2
3
4
5
6
7
from sqlalchemy.sql import select
s = select([users])
result = conn.execute(s)
--
2018-12-24 14:16:11,363 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.fullname
FROM users
2018-12-24 14:16:11,363 INFO sqlalchemy.engine.base.Engine ()

結果のパース。タプルライクに取得。

1
2
3
4
5
for row in result:
print(row)
--
(1, 'jack', 'Jack Jones')
(2, 'wendy', 'Wendy Williams')

辞書ライクに取得。

1
2
3
4
5
result = conn.execute(s)
row = result.fetchone()
print("name:", row['name'], "; fullname:", row['fullname'])
--
name: jack ; fullname: Jack Jones

conn.execute()の結果はイテレータっぽく扱えるので以下のような書き方ができる。 今回は2個のテーブルのカルテシアン積を求める例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for row in conn.execute(select([users, addresses])):
print(row)
--
2018-12-24 14:20:14,164 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users, addresses
2018-12-24 14:20:14,164 INFO sqlalchemy.engine.base.Engine ()
(1, 'jack', 'Jack Jones', 1, 1, 'jack@yahoo.com')
(1, 'jack', 'Jack Jones', 2, 1, 'jack@msn.com')
(1, 'jack', 'Jack Jones', 3, 2, 'www@www.org')
(1, 'jack', 'Jack Jones', 4, 2, 'wendy@aol.com')
(2, 'wendy', 'Wendy Williams', 1, 1, 'jack@yahoo.com')
(2, 'wendy', 'Wendy Williams', 2, 1, 'jack@msn.com')
(2, 'wendy', 'Wendy Williams', 3, 2, 'www@www.org')
(2, 'wendy', 'Wendy Williams', 4, 2, 'wendy@aol.com')

どちらかというと、こちらの方がイメージに近いか。

1
2
3
4
5
6
7
8
9
10
11
for row in conn.execute(select([users, addresses]).where(users.c.id == addresses.c.user_id)):
print(row)
--
2018-12-24 14:22:46,769 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users, addresses
WHERE users.id = addresses.user_id
2018-12-24 14:22:46,769 INFO sqlalchemy.engine.base.Engine ()
(1, 'jack', 'Jack Jones', 1, 1, 'jack@yahoo.com')
(1, 'jack', 'Jack Jones', 2, 1, 'jack@msn.com')
(2, 'wendy', 'Wendy Williams', 3, 2, 'www@www.org')
(2, 'wendy', 'Wendy Williams', 4, 2, 'wendy@aol.com')

オペレータの結合

and_などを用いる例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sqlalchemy.sql import and_, or_, not_
s = select([(users.c.fullname +
", " + addresses.c.email_address).
label('title')]).\
where(
and_(
users.c.id == addresses.c.user_id,
users.c.name.between('m', 'z'),
or_(
addresses.c.email_address.like('%@aol.com'),
addresses.c.email_address.like('%@msn.com')
)
)
)
conn.execute(s).fetchall()

Pythonの演算子を用いる例。

1
2
3
4
5
6
7
8
9
10
11
12
s = select([(users.c.fullname +
", " + addresses.c.email_address).
label('title')]).\
where(
(users.c.id == addresses.c.user_id) &
(users.c.name.between('m', 'z')) &
(
addresses.c.email_address.like('%@aol.com') | \
addresses.c.email_address.like('%@msn.com')
)
)
conn.execute(s).fetchall()

and_はwhere句を並べることでも実現できる。

1
2
3
4
5
6
7
8
9
10
11
12
s = select([(users.c.fullname +
", " + addresses.c.email_address).
label('title')]).\
where(users.c.id == addresses.c.user_id).\
where(users.c.name.between('m', 'z')).\
where(
or_(
addresses.c.email_address.like('%@aol.com'),
addresses.c.email_address.like('%@msn.com')
)
)
conn.execute(s).fetchall()

テキストで実行

基本的な使い方

1
2
3
4
5
6
7
8
9
from sqlalchemy.sql import text
s = text(
"SELECT users.fullname || ', ' || addresses.email_address AS title "
"FROM users, addresses "
"WHERE users.id = addresses.user_id "
"AND users.name BETWEEN :x AND :y "
"AND (addresses.email_address LIKE :e1 "
"OR addresses.email_address LIKE :e2)")
conn.execute(s, x='m', y='z', e1='%@aol.com', e2='%@msn.com').fetchall()

予めバインドされた値を予め定義することもできる。

1
2
3
4
5
6
7
stmt = text("SELECT * FROM users WHERE users.name BETWEEN :x AND :y")
stmt = stmt.bindparams(x="m", y="z")
# stmt = stmt.bindparams(bindparam("x", type_=String), bindparam("y", type_=String))
result = conn.execute(stmt, {"x": "m", "y": "z"})
result.fetchall()
--
[(2, 'wendy', 'Wendy Williams')]

ステートメントの中でSQLテキストを用いることもできる。

1
2
3
4
5
6
7
8
9
10
11
12
13
s = select([
text("users.fullname || ', ' || addresses.email_address AS title")
]).\
where(
and_(
text("users.id = addresses.user_id"),
text("users.name BETWEEN 'm' AND 'z'"),
text(
"(addresses.email_address LIKE :x "
"OR addresses.email_address LIKE :y)")
)
).select_from(text('users, addresses'))
conn.execute(s, x='%@aol.com', y='%@msn.com').fetchall()

グループ

単純な例

1
2
3
4
5
6
7
from sqlalchemy import func
stmt = select([
addresses.c.user_id,
func.count(addresses.c.id).label('num_addresses')]).\
group_by("user_id").order_by("user_id", "num_addresses")

conn.execute(stmt).fetchall()

結合

単純な例

1
print(users.join(addresses))

いろいろな表現を用いることができる。

1
2
3
4
print(users.join(addresses,
addresses.c.email_address.like(users.c.name + '%')
)
)

実施に実行

1
2
3
4
5
6
7
8
9
10
s = select([users.c.fullname]).select_from(
users.join(addresses,
addresses.c.email_address.like(users.c.name + '%'))
)
conn.execute(s).fetchall()
--
2018-12-25 12:45:29,919 INFO sqlalchemy.engine.base.Engine SELECT users.fullname
FROM users JOIN addresses ON addresses.email_address LIKE users.name || ?
2018-12-25 12:45:29,919 INFO sqlalchemy.engine.base.Engine ('%',)
[('Jack Jones',), ('Jack Jones',), ('Wendy Williams',)]

outer join

1
2
3
4
print(select([users.c.fullname]).select_from(users.outerjoin(addresses)))
--
SELECT users.fullname
FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id

変数バインド

単純な例

1
2
3
4
5
6
7
8
from sqlalchemy.sql import bindparam
s = users.select(users.c.name.like(bindparam('username', type_=String) + text("'%'")))
conn.execute(s, username='wendy').fetchall()
--
2018-12-25 13:34:19,392 INFO sqlalchemy.engine.base.Engine SELECT users.fullname
FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
2018-12-25 13:34:19,392 INFO sqlalchemy.engine.base.Engine ()
[('Jack Jones',), ('Jack Jones',), ('Wendy Williams',), ('Wendy Williams',)]

バインドした変数は複数回使用できる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
s = select([users, addresses]).\
where(
or_(
users.c.name.like(
bindparam('name', type_=String) + text("'%'")),
addresses.c.email_address.like(
bindparam('name', type_=String) + text("'@%'"))
)
).\
select_from(users.outerjoin(addresses)).\
order_by(addresses.c.id)
conn.execute(s, name='jack').fetchall()
--
2018-12-25 13:43:43,880 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
WHERE users.name LIKE ? || '%' OR addresses.email_address LIKE ? || '@%' ORDER BY addresses.id
2018-12-25 13:43:43,880 INFO sqlalchemy.engine.base.Engine ('jack', 'jack')
[(1, 'jack', 'Jack Jones', 1, 1, 'jack@yahoo.com'), (1, 'jack', 'Jack Jones', 2, 1, 'jack@msn.com')]

その他の機能

  • ファンクション
  • ウィンドウファンクション
  • union、except_
  • Label
  • Ordering, Limiting, ...

Update

1
2
3
4
5
stmt = users.update().\
where(users.c.name == 'jack').\
values(name='ed')

conn.execute(stmt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
stmt = users.update().\
where(users.c.name == bindparam('oldname')).\
values(name=bindparam('newname'))
conn.execute(stmt, [
{'oldname':'jack', 'newname':'ed'},
{'oldname':'wendy', 'newname':'mary'},
{'oldname':'jim', 'newname':'jake'},
])
conn.execute(select([users])).fetchall()
--
2018-12-25 15:11:08,628 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.fullname
FROM users
2018-12-25 15:11:08,628 INFO sqlalchemy.engine.base.Engine ()
[(1, 'ed', 'Jack Jones'), (2, 'mary', 'Wendy Williams')]
共有

Flask SQLAlchemy

参考

シェルで動作確認

Dockerコンテナのビルド

Flask on Dockerのブログ と同様にDockerfileを作り、ビルドする。

ファイルを作成

1
2
3
4
5
6
7
8
9
10
$ mkdir -p  ~/Sources/docker_flask/sqlalchemy
$ cd ~/Sources/docker_flask/sqlalchemy
$ cat << EOF > Dockerfile
FROM ubuntu:latest

RUN apt-get update
RUN apt-get install python3 python3-pip -y

RUN pip3 install flask flask_sqlalchemy
EOF

ビルド

1
$ sudo docker build . -t dobachi/flask_sqlalchemy:1.0

アプリ作成と実行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ mkdir apps
$ cat << EOF > apps/app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)

def __repr__(self):
return '<User %r>' % self.username
EOF

シェルを起動する。

1
$ sudo docker run -it --rm -p 5000:5000 -v $(pwd)/apps:/usr/local/apps -e "FLASK_APP=app.py" -w /usr/local/apps -e "LC_ALL=C.UTF-8" -e "LANG=UTF-8" dobachi/flask_sqlalchemy:1.0 /bin/bash

シェル内で動作確認。テーブルを作ってレコードを生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> from app import db
/usr/local/lib/python3.6/dist-packages/flask_sqlalchemy/__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
>>> db.create_all()
>>> from app import User
>>> admin = User(username='admin', email='admin@example.com')
>>> guest = User(username='guest', email='guest@example.com')
>>> db.session.add(admin)
>>> db.session.add(guest)
>>> db.session.commit()
>>> User.query.all()
[<User 'admin'>, <User 'guest'>]
>>> User.query.filter_by(username='admin').first()
<User 'admin'>

sqlite3コマンドで接続して内容を確認。

1
2
3
4
5
6
7
8
9
root@a5d5ee81df78:/usr/local/apps# apt install sqlite3
root@a5d5ee81df78:/usr/local/apps# sqlite3 /tmp/test.db
sqlite> .databases
main: /tmp/test.db
sqlite> .tables
user
sqlite> select * from user;
1|admin|admin@example.com
2|guest|guest@example.com

アプリから動作確認

上記と同様の流れをアプリから動作確認する。 Dockerイメージは上記で作ったものをベースとする。

アプリ作成

ここでは/registにアクセスすると、登録画面が出て、 登録するとリスト(/list)が表示されるアプリを作成する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
$ mkdir -p  ~/Sources/docker_flask/sqlalchemy_app
$ cd ~/Sources/docker_flask/sqlalchemy_app
$ mkdir apps
$ cat << EOF > apps/app.py
from flask import Flask, url_for, request, render_template, redirect
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)

def __repr__(self):
return '<User %r>' % self.username

db.create_all()

@app.route('/regist', methods=['POST', 'GET'])
def regist():
if request.method == 'POST':
user = User(username=request.form['username'], email=request.form['email'])
db.session.add(user)
db.session.commit()
return redirect(url_for('list'))
# the code below is executed if the request method
# was GET or the credentials were invalid
return render_template('regist.html')

@app.route('/list')
def list():
users = User.query.order_by(User.username).all()
return render_template('list.html', users=users)
EOF
$ mkdir -p apps/templates
$ cat << EOF > apps/templates/regist.html
<!doctype html>
<title>Registration</title>
<form action="/regist" method="post">
<div>username: <input type="text" name="username"></div>
<div>email: <input type="text" name="email"></div>
<input type="submit" value="send">
<input type="reset" value="reset">
</form>

<a href="/list">list</a>
EOF
$ cat << EOF > apps/templates/list.html
<!doctype html>
<title>List ordered by username</title>
<table>
<thead>
<tr>
<th>id</th>
<th>username</th>
<th>email</th>
</tr>
</thead>
<tbody>
{% for item in users %}
<tr>
<td>
{{ item.id }}
</td>
<td>
{{ item.username }}
</td>
<td>
{{ item.email }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="/regist">registration</a>
EOF

実行

1
$ sudo docker run -it --rm -p 5000:5000 -v $(pwd)/apps:/usr/local/apps -e "FLASK_APP=app.py" -w /usr/local/apps -e "LC_ALL=C.UTF-8" -e "LANG=UTF-8" dobachi/flask_sqlalchemy:1.0 flask run --host 0.0.0.0

なお、上記の実装はエラーハンドリング等を一切実施していないので 例えば同じユーザ名、メールアドレスで登録しようとすると例外が生じる。

共有

tmux_rectangle_select

参考

方法

tmuxを使ってコピーするとき、矩形選択したいときがある。 矩形選択にも言及のあるブログ にも記載あるが、 <prefix> + [ でコピーモードに入った後、 該当箇所まで移動し、スペースキーを押して選択開始、その後 v を押すと矩形選択になる。 (初期状態では、行選択になっているはず)

共有