<Python, flask> REST APIをやってみた。。。

前から気になっていた、REST APIFlask-SQLAlchemy
サンプルコードを作ってみた。

http://127.0.0.1/sqlalc/id/name/looksの情報を、Json{"id": id, "name": name, "looks":looks}にして、通信+SQLデータベースに取り込む。
GET + /id/name/*/SQLからJsonゲット!
PUT + /-/name/looks/SQLにデータプット!
DELETE + /id/-/-/SQLからデータデリート!

実際に動かしてみた。

1... まずは適当な端末で、restapi.py を走らせる。

>py restapi.py
 * Running on http://127.0.0.1:8000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: xxx-xxx-xxx

2... で、別の端末で、まずは、データベースをチェックする。

>curl -i http://127.0.0.1:8000/sqlalc/
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 40
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:02:54 GMT

{
  "data": [],
  "r": "GET success"
}

3... ほんでもって、PUT with id = '1'。で、fail。idではPUTできないことにしてるから、、

>curl -i http://127.0.0.1:8000/sqlalc/1/Taro/Hage -X PUT
HTTP/1.0 403 FORBIDDEN
Content-Type: application/json
Content-Length: 49
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:03:14 GMT

{
  "id": "1",
  "r": "PUT fail, no id found"
}

4... と、いうことで、再度PUT with id = '-'。そうすっと、success

> curl -i http://127.0.0.1:8000/sqlalc/-/Taro/Hage -X PUT
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 76
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:03:32 GMT

{
  "id": 1,
  "looks": "Hage",
  "name": "Taro",
  "r": "PUT success"
}

5... PUT もういっちょう。

>curl -i http://127.0.0.1:8000/sqlalc/-/Jiro/MottoHage -X PUT
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 81
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:03:43 GMT

{
  "id": 2,
  "looks": "MottoHage",
  "name": "Jiro",
  "r": "PUT success"
}

6... データベースチェック。

>curl -i http://127.0.0.1:8000/sqlalc/
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 196
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:03:50 GMT

{
  "data": [
    {
      "id": 1,
      "looks": "Hage",
      "name": "Taro"
    },
    {
      "id": 2,
      "looks": "MottoHage",
      "name": "Jiro"
    }
  ],
  "r": "GET success"
}

7... GET id = '1。'

>curl -i http://127.0.0.1:8000/sqlalc/1/-/-
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 76
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:04:04 GMT

{
  "id": 1,
  "looks": "Hage",
  "name": "Taro",
  "r": "GET success"
}

8... か、 GET with name = 'Taro'

>curl -i http://127.0.0.1:8000/sqlalc/-/Taro/-
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 76
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:04:17 GMT

{
  "id": 1,
  "looks": "Hage",
  "name": "Taro",
  "r": "GET success"
}

9... あとは、削除。DELETE with id = '1'

>curl -i http://127.0.0.1:8000/sqlalc/1/-/- -X DELETE
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 28
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:04:29 GMT

{
  "r": "DELETE success"
}

10... データベースチェック。

>curl -i http://127.0.0.1:8000/sqlalc/
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 121
Server: Werkzeug/0.11.4 Python/3.5.3
Date: Sun, 03 Dec 2017 13:04:34 GMT

{
  "data": [
    {
      "id": 2,
      "looks": "MottoHage",
      "name": "Jiro"
    }
  ],
  "r": "GET success"
}

あと、Flask-RESTfulも試してみた。

けど、なんだか、使わない場合とコードの差があまりなかった。。。
これだと、あまり使わないかな、、、

参考にさせてもらったところ。
qiita.com

qiita.com

qiita.com

マニュアル。

Flask-SQLAlchemy — Flask-SQLAlchemy Documentation (2.3)

Flask-RESTful — Flask-RESTful 0.3.6 documentation

<Python, flask> endpointとは、、、

Flaskさんで使われている語句 endpointって何? と思った。
調べてみた。

stackoverflow.com

いつも頼りになるstackoverflowさん。
最初の回答はよくわからなかったが、2回目の回答を試す。

In [1]: from flask import Flask, url_for
   ...: 
   ...: app = Flask(__name__)
   ...: 
   ...: # We can use url_for('foo_view') for reverse-lookups in templates or view functions
   ...: @app.route('/foo')
   ...: def foo_view():
   ...:     pass
   ...: 
   ...: # We now specify the custom endpoint named 'bufar'. url_for('bar_view') will fail!
   ...: @app.route('/bar', endpoint='bufar')
   ...: def bar_view():
   ...:     pass
   ...: 

In [3]: with app.test_request_context('/'):
   ...:     print(url_for('foo_view'))
   ...:     print(url_for('bufar'))
   ...:     
/foo
/bar

In [4]: with app.test_request_context('/'):
   ...:     print(url_for('bar_view'))
   ...:     
---------------------------------------------------------------------------
BuildError                                Traceback (most recent call last)
:

ふーん、、、で、ちと思い出したapp.url_mapをする。

In [5]: app.url_map
Out[5]: 
Map([<Rule '/foo' (GET, HEAD, OPTIONS) -> foo_view>,
 <Rule '/bar' (GET, HEAD, OPTIONS) -> bufar>,
 <Rule '/static/<filename>' (GET, HEAD, OPTIONS) -> static>])

In [6]: def hage():
   ...:     return 'Hage!'
   ...: 

In [7]: app.add_url_rule('/hogehoge', 'hage', hage)

In [8]: app.url_map
Out[8]: 
Map([<Rule '/hogehoge' (GET, HEAD, OPTIONS) -> hage>,
 <Rule '/foo' (GET, HEAD, OPTIONS) -> foo_view>,
 <Rule '/bar' (GET, HEAD, OPTIONS) -> bufar>,
 <Rule '/static/<filename>' (GET, HEAD, OPTIONS) -> static>])

なるへそう。
なんとなく、、endpointは、url_forURL一覧app.url_mapから、対象のURLを探す時のキーっぽい。
デフォルトは、@app.route()で、デコレートされたview function

マニュアルさんも。
http://flask.pocoo.org/docs/0.12/api/#flask.Flask.add_url_rule

過去記事 url_for nekoyukimmm.hatenablog.com

<Python, class> __dict__で少し遊ぶ。

class.__dict__で少し遊んでみた。

Pythonさんだと、class作成時にインスタンス変数instance variableを準備しなくても、後付けで追加可能とのこと。

クラス作成+インスタンス作成。

In [46]: class Hage():
    ...:     def __init__(self, name):
    ...:         self.name = name
    ...:         

In [49]: hage = Hage('Taro')

で、.__dict__する。と、インスタンスで持っている、dictが出てくる。こりゃ便利。

In [50]: hage.__dict__
Out[50]: {'name': 'Taro'}

で、後付けで変数追加。

In [51]: hage.looks = 'Turupika'

In [52]: hage.__dict__
Out[52]: {'looks': 'Turupika', 'name': 'Taro'}

いいねー。
関数も後付け可能とのこと。

In [58]: def flash2(self):
    ...:     print('Flash2!')
    ...:     

In [59]: Hage.flash2 = flash2

In [60]: hage.flash2()
Flash2!

In [63]: hage.__dict__
Out[63]: {'flash': <function __main__.flash>, 'looks': 'Turupika', 'name': 'Taro'}

要素削るのは、.__delattr__

In [64]: hage.__delattr__('looks')

In [65]: hage.__dict__
Out[65]: {'flash': <function __main__.flash>, 'name': 'Taro'} 

なるほどねー。

参考にさせてもらいました。
y0m0r.hateblo.jp

<msys2, pacman> mingw32, mingw64 をきる。

msys2pacman -Syuした時に、mingw32 mingw64も更新される。
使わないので切りたいな、、と思ってた。
/etc/pacman.confをいじればいいとのこと。

Color

#[mingw64]
#Include = /etc/pacman.d/mirrorlist.mingw64

mingw64コメントアウトする。

qiita.com

<Python, seaborn> seaborn-data

seaborn-data、、、
seabornの作者さんが準備している、seabornで使えるデータコレクション。

github.com

上記から、ダウンロードして、使える。

In [15]: import seaborn as sns

In [16]: sns.load_dataset?
Signature: sns.load_dataset(name, cache=True, data_home=None, **kws)
Docstring:
Load a dataset from the online repository (requires internet).

Parameters
----------
name : str
    Name of the dataset (`name`.csv on
    https://github.com/mwaskom/seaborn-data).  You can obtain list of
    available datasets using :func:`get_dataset_names`
cache : boolean, optional
    If True, then cache data locally and use the cache on subsequent calls
data_home : string, optional
    The directory in which to cache data. By default, uses ~/seaborn_data/
kws : dict, optional
    Passed to pandas.read_csv
File:      c:\anaconda3\lib\site-packages\seaborn\utils.py
Type:      function

In [17]: type(sns.load_dataset('dots'))
Out[17]: pandas.core.frame.DataFrame

In [18]: df = sns.load_dataset('dots')

In [19]: df.head()
Out[19]: 
  align choice  time  coherence  firing_rate
0  dots     T1   -80        0.0    33.189967
1  dots     T1   -80        3.2    31.691726
2  dots     T1   -80        6.4    34.279840
3  dots     T1   -80       12.8    32.631874
4  dots     T1   -80       25.6    35.060487

便利だ。