u-ryo's blog

various information for coding...

Category: Python

Get Refresh Token for Google API

| Comments

何かいつの間にかGoogle APIの認証方法が変わってて、security上の理由からというので仕方ないんでしょうけど。

AUTHORIZATION_CODEを得ようと、以前のように↓のURLにaccessすると、 https://accounts.google.com/o/oauth2/v2/auth?responsetype=code&clientid=...apps.googleusercontent.com&redirecturi=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/photoslibrary&accesstype=offline アクセスをブロック: ... のリクエストは無効です

と出て、あれ?!と。

エラー 400: invalid_request The out-of-band (OOB) flow has been blocked in order to keep users secure. Follow the Out-of-Band (OOB) flow migration guide linked in the developer docs below to migrate your app to an alternative method.

で、帯域外(OOB)フロー移行ガイドへ誘導され。

このoobフローはなくなったと!? んじゃどうせぃっていうんじゃねん。

「デスクトップクライアント」に相当するから、ループバック IP アドレス(localhost または 127.0.0.1)フローに飛ばされたものの、こっちもなくなってて、ループバック IP アドレスフローの移行ガイドに飛ばされて、結局library使う方法しか書いてなくて。こちとら、shell scriptで使いたいんですけど。refresh_token欲しいだけなのに、なんでこんなに苦労せなかんの??🤔

...って嘆いても仕方ないので、library使ってrefresh_token取得だけします。

ちょっとめんどくさいんですけど、local環境を汚染しない形で。

参考:

Google APIの認証情報のpageから「OAuthクライアントをダウンロード」してclient_secret.jsonとして保存。

1
2
3
4
5
6
7
$ docker run --rm -it -v $PWD/client_secret_....json:/root/client_secret.json python:alpine sh
# apk add w3m screen
# pip install google-api-python-client google-auth-oauthlib
# screen
# python
>>> from google_auth_oauthlib.flow import InstalledAppFlow
>>> credential=InstalledAppFlow.from_client_secrets_file('client_secret.json',["https://www.googleapis.com/auth/photoslibrary.appendonly"]).run_local_server()

ここでw3mが開くので、Qを押して閉じるとURLが表示され、そこをChromeなりで開いて、突き進んで承認します。

そうすると、http://localhost:8080/?state=.... へ回されて止まるので、C-aで別screenを開いて、そこでw3m 'http://localhost:8080/?state=...'とすると、The authentication flow has completed. You may close this window.と言われます。徐に元のscreenに戻るとcredential objectができているので、credential.refresh_tokenとすると、漸くREFRESH_TOKENを得られます。1時間有効なACCESS_TOKENcredentail.tokenで得られます。

これらを使うと、やっと以前のようにshell scriptで回せるようになります。ふぅ。

Learn Python 3 the Hard Way

| Comments

知人がLearn Python 3 the Hard Way翻訳しました。 凄いなぁと思うと同時に、 見てみると既に英語版勉強した人がいるというので、 その人がやったという初心者用練習問題を、 ジャニヲタじゃないので、 というか初心者ではないので「一行で」やってみました。

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
>>> def average_age(members):
...  return sum([x[2] for x in members])/len(members)
...
>>> average_age([('s','s',35),('a','a',34),('n','n',34),('d','o',36),('j','j',34)])
34.6

>>> def oldest_member(members):
...  return max(members, key=(lambda x:x[2]))[0]
...
>>> oldest_member([('s','s',35),('a','a',34),('n','n',34),('d','o',36),('j','j',34)])
'd'

>>> def second_oldest_member(members):
...  return sorted(members, key=(lambda x:x[2]))[1][0]
...
>>> second_oldest_member([('s','s',35),('a','a',34),('n','n',34),('d','o',36),('j','j',34)])
'n'

>>> def next_older_member(members, nickname):
...  return min([a for a in members if a[2] > [b for b in members if b[0]==nickname][0][2]],key=(lambda x:x[2]))[0]
...
>>> next_older_member([('st','ms',19),('m','my',17),('k','nk',23),('f','kf',22),('sh','ss',20)],'f')
'k'

>>> def check_future_age(current_members, future_members):
...  return len({i[2]-j[2] for i,j in zip(current_members,future_members)}) == 1
...
>>> check_future_age([('st','ms',19),('m','my',17),('k','nk',23),('f','kf',22),('sh','ss',20)],[('st','ms',22),('m','my',20),('k','nk',26),('f','kf',25),('sh','ss',23)])
True
>>> check_future_age([('st','ms',19),('m','my',17),('k','nk',23),('f','kf',22),('sh','ss',20)],[('st','ms',22),('m','my',20),('k','nk',26),('f','kf',25),('sh','ss',24)])
False

あぁ、なんてアホなことに時間と頭を使ってしまった...

minmaxsortedってリスト内包表記で出来ないんですか?

印税は初版で20〜30万、あとは増刷でガッポガッポ、だそうです。 1年半かかったって。お疲れさまでした。 ぼくも販促に協力しましょうかね。 そしておこぼれにあずかれれば!

Python Basic Web Server for Applying Keras Model

| Comments

VGG16をfine tuningしたmodelを簡単にapply(predict)するsystemが NotePC程度で動くことを証明したく、 PythonのBaseHTTPServerで1日でちゃちゃっと作りました。

といっても「PythonのBaseHTTPServer」なんて触るの初めてです。 bradmontgomery/dummy-web-server.pyを参考にしました。 なるほど、classを定義して、BaseHTTPRequestHandlerを引数にして、 do_GETdo_POSTを書くわけですね。 routingは自分でやれと。面倒なのでmethodで分けました。 このsystem自体をone fileで済ませたかったので、 GETindex.htmlを返したいと思い、 そのためにはhere documentを書きたいな、 と思ったので、 Pythonのヒアドキュメントを参考に、 あぁ、普通に'''(single quote 3つ)でいいのね、とわかりました。 single quoteでも中で変数展開されるんですね。へー。 PythonでJSONを受けて処理をするを参考に、 POST時のparameter(=request body)の受け取り方を。 HTTP Request HeaderのContent-Lengthintとして記憶し、 self.rfile.read()でそのbyte分読んで、 decode()でstringにすると。 parameterizedされるわけではなく、bodyがまるっと読まれるので、 parameterで分けるのは自分でやれということですね。

あと、base64として来た文字列をdecodeしてImage化するには、 先頭のimage/jpeg;base64,を除去し(replace())て純粋にBase64文字列だけにし、 base64.b64decode(content)したものをio.BytesIO()し、 それをImage.open()すると。

predict()したものは2次元配列になっているので、 0番目のargmax()したものが答えの添字、なのですね。

ともあれ、このpython predict server script 1つと keras model fileの2 filesだけでサクッと動くものを、 githubに置きました。

Push Notification From Command Line by Ntfy

| Comments

コマンドラインからPush通知が出来るというのでやってみました。 (Linuxのコマンドラインやスクリプトからスマホにプッシュ通知する。(ntfyというツールの紹介)) PushBulletを使ってみました。 ChromeやFirefoxだとextension、 スマホだとアプリを入れます。

1
2
sudo apt install python-pip
pip install ntfy

ntfyを入れ、~/.ntfy.ymlにPushBulletのaccess_tokenを入れ、 ~/.local/bin/ntfy -t 'Title' send 'notification contents' とすると、送れました。 スマホ側の音とか振動は、アプリでの設定にて調整可能です。

最初よくわかってなかったのですが、 PushBulletのアプリを入れると、 電話帳やSMS(Short Message Service)もぶっこ抜いてくるんですね。 それと知らずにSMS送ってしまい、相手に不審がられてしまいました。

Learning Ruby and Python3

| Comments

paiza learningのRuby入門編のコース、一部が期間限定無料だったので、やってみました。 女の子の声、何かいいですね。 内容は「入門編」だけにifやloopやarray等ホントに基本的なことで、ぼくには易しすぎですけど、演習問題で学習内容を確認出来るのがいい感じです。ただ、まだ有料部分もあり、そういう所は動画が見られないのは当然としても、演習問題も出来ないとは。 物足りないので、python3の入門編もやっちゃいました。こちらは全編無料ですし。でも、やっぱりホント基本的なことですね。あと、rubyとpython、同時にやるもんじゃないです。putsとかprintは勿論、getsinput()elsifelif等、色々ごっちゃになっちゃいます。rubyの方が後発のいいとこ取りなだけに、配列範囲外アクセスでもエラーにしない等洗練されてる印象。ただ、putsgetsは英語がヘン、というか独特な気が。日本人だから? 紹介されてたrubyのfor loop(each do |x| ... end)は、doと書かないでeach{|x|...}と書けばJava8のStreamingと同じなんですね。eachってmapとかと同じ。なるほど、最初からそうなってるんだ、と納得です。