Category Archives: Python

[メモ] SlackとMattermostそれぞれのincomingWebhookへのポスト方法の違い

Pocket

MattermostはSlackのクローンであるが、incomingWebhookへのポストだけは、どうも違いがあるようだ。
以下にSlack/Mattermostそれぞれでの実例を示す。
まずmattermost

# mattermost

import requests

incomWebHook = 'http://192.168.10.1/hooks/xxxxx'
msg = 'test message'
icon_url = 'http://192.168.10.10/graphix/robot.png'
username = 'bot'

def sendMsg(incomWebHook, icon_url, username, msg):
    payload = {
            'text': msg,
            'icon_url': icon_url,
            'username': username}

    r = requests.post(
        incomWebHook,
        json=payload)

    return r

r = sendMsg(incomWebHook, icon_url, username, msg)

Slack

# slack
import requests

incomWebHook ="https://slack.com/api/chat.postMessage"
msg = 'test message'
username = 'bot'
token = "xoxb-xxxx-xxxx"

def sendMsg(incomWebHook, token, username, msg):
    payload_dic = {
            "token": token
            "type": "message",
            "channel": "#general",
            "text": msg,
            "username": username,
            "icon_emoji": ":bird:",
            }

    headers = {
            'Content-type': 'application/json',
            'Accept': 'text/plain'
            }

    r = requests.post(
            incomWebHook,
            params=payload_dic,
            headers=headers)

    return r

r = sendMsg(incomWebHook, token, username, msg)

[メモ][Python] AnacondaをWindows xpにインストールしようとすると失敗する

Pocket

Anacondaは、Pythonのほかに、IPython、Spyder、pandas他便利ライブラリが一式でついてくるお手軽Python環境である。

しかしAnacondaをWindows xpにインストールしようとすると失敗する。
具体的には、インストール途中の「メニューを作る」ステップで失敗。
無視して進めると、C:\Anaconda3に実行ファイルは揃っているので、「なんだ気のせいか」と安心して起動しようとすると「有効なWin32アプリケーションではありません」という旨のエラーが発生する。

原因は、最新版がxpに対応していないせい。
以下から2.2.0をダウンロードし、インストールする。

https://repo.continuum.io/archive/

念のためファイル名とハッシュ値も残す。

Anaconda3-2.2.0-Windows-x86.exe
7c49a4e76e1c383038c4a1e8c4ac506f

Anaconda-2.2.0-Windows-x86.exe
32246b48658d4c3faeef425cec64a131

AnacondaのFAQにしっかり記載がある。

https://docs.continuum.io/anaconda/faq

How can I use Anaconda on Windows XP?
Windows XP is supported on Anaconda versions 2.2 and earlier. Download it from our archive.

Slack/MattermostのbotをPythonのFlaskで作ろう

Pocket

Slack/Mattermost(以降、まとめてSlack)のbotといえばHubotが有名だ。
Hubotはcoffeescriptで書かれているのだが、botのためだけに新しい言語を覚えるのも面倒。
加えてHubotを動作させるにはnpmが必要。
ちょっとそこまでは…。
Pythonなら普段使いで最初から環境は作ってあるし、楽だし。
そう思っていろいろと調べてみた。

Slackのbotに必要なことは?

Slackのbotに必要なのは、端的に以下の二つ。
1. Slackからのデータ送信を受ける。
2. Slackへ何かをする。

1.は、HTTP POSTでやってくるので、POSTを受けることさえできればよい。
2.は、例えばSlack上で何かの発言をすることだが、こちらはcurl(Pythonならrequests)でも使えば簡単にできる。

PythonでHTTP POSTを受けるには?

Flaskである。
Flaskとはごくごく軽量なwebフレームワークである。
驚くくらい簡単にwebサーバを作ることができる。
もちろんPOSTを受けるのもすぐにできる。
以下、説明。

Flaskのインストール

pipでもなんでも、好きなものを使ってインストールせい。

Flaskのテスト

以下のようなスクリプトを書く。
適当な名前で保存する。
flask.pyとかはやめようね。

#!/usr/local/bin/python

from flask import Flask

app = Flask(__name__)

@app.route('/')
def welcome():
    html = '<html><title>welcome</title>'
    html = html + '<body>welcome</body></html>'
    return html

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0')

上記のapp.route(‘/’)とは、ルーティング。
ルートディレクトリ(’/’)へのアクセスがあったら、次のdef welcome()が(デコレートによって)呼ばれる、ということである。

上記の場合、welcomeと表示するhtmlが返る。

app.debug = Trueについては後述。
app.run(host=’0.0.0.0)のhost=…の記述により、サーバを外部に公開することになる。

テストスクリプトの実行

$ python ./flasktest.py
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 213-546-048

localhostのポート5000でサーバが立ち上がったと分かる。
ブラウザでアクセスして「welcome」と表示されればよい。

ところで、app.debut = Trueだが、スクリプトを書き換えると、自動的に再読み込みをしてくれる。
実際のログは以下。

 * Detected change in '/usr/home/doe/py/flasktest.py', reloading
 * Restarting with stat
 * Debugger is active!

激烈に便利な機能なので、開発中は有効にしておくこと。

SlackからのPOSTを受ける。

先ほどのスクリプト冒頭のimportを以下のように変更。

from flask import Flask, request

さらに以下を追加。

@app.route('/matter', methods=['POST'])
def post():
    print request.form

上記のようにしておいて、Slack側のOutgoing Webhookで、呼び出すURLに「http://<あなたのサーバのアドレス>:5000/matter」を指定する。

Slack側からwebhookを呼び出してみると、POSTされた内容がログに表示されるはず。
なお、def post()が何も返さないのでエラーは出るが気にしない。

以下が例。

ImmutableMultiDict([('user_id', u'xxxxx'), ('channel_id', u'xxxxx'), ('timestamp', u'1414562326'), ('team_id', u'xxxx'), ('trigger_word', u'test'), ('channel_name', u'off-topic'), ('token', u'xxxtokenxxx'), ('text', u'test'), ('team_domain', u'xxxx'), ('user_name', u'xxxx')])

つまりPOSTの内容はディクショナリになっている。

Slackへ応答を返そう

Slackへ応答を返す場合には、POSTでもらった中にあるtokenが必要である。
応答文、tokenのディクショナリを作っておいて、それをjsonに変換し、返してやればよい。
Mattermostの場合、tokenのキーは’MATTERMOST_TOKEN’

先ほどのスクリプトを最終的に以下のようにする。
(わざわざjsonをimportしているが、Flaskにもそういう機能がある気がしてならない)
これでSlackから通知を受けると、「You said <トリガーワード>」という応答がSlackへ帰る。

#!/usr/local/bin/python

from flask import Flask, request
import requests
import json

app = Flask(__name__)

@app.route('/')
def welcome():
    html = '<html><title>welcome</title>'
    html = html + '<body>welcome</body></html>'
    return html

@app.route('/matter', methods=['POST'])
def post():
    postdic = request.form
    incomeText = postdic['text']
    token = postdic['token']
    text = 'You said ' + incomeText

    payload = {
            'text': text,
            'MATTERMOST_TOKEN': token}
    json_payload = json.dumps(payload)
    return json_payload

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0')

あとはどんどん膨らませていけばよい。

 

[Python] listの差分を知るには

Pocket

Pythonで、二つのリストの差分を知るには。
リストのままでは引き算ができない。
set()でset型にしてから引き算をする。
ただしset()すると、与えられたリストから重複した要素が除かれること、順序も保持されないことに注意
また、set()して要素を操作した結果はset型のまま。
list()でリストに戻す必要がある。

以下、サンプル。

>>> a = ["a"]
>>> b = ["b","c","d"]
>>> b - a
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for -: 'list' and 'list'
>>> c = list(set(b) - set(a))
>>> c
['c', 'b', 'd']
>>> c.sort()
>>> c
['b', 'c', 'd']

[Python][memo] タイムスタンプの差を求める

Pocket

すぐ忘れるのでメモ。

文字列としてのタイムスタンプは、datetime.datetime.strptimeで、フォーマットを指定してdatetime.datetime型に変換。
そうしたら加減算ができる。datetime.timeでは出来ないので注意。
以下、IPythonでの例。

In [1]: from datetime import datetime

In [2]: t1 = datetime.strptime("14:36:02.0689", "%H:%M:%S.%f")

In [3]: t2 = datetime.strptime("14:36:03.0102", "%H:%M:%S.%f")

In [4]: print type(t1)


In [5]: delta = t2 - t1

In [6]: print str(delta)
0:00:00.941300

In [7]: print str(delta)[6:]
0.941300

In [8]: 

[Python] requestsとlxmlで京急の運行情報を抽出しよう

Pocket

botに京急の運行情報を調べさせて、Slackで発言させたい。
使用言語はPython。
さあどうしようかと思ったら、さいきんは、どんなものでもライブラリが揃っていて、あっという間になんでも出来てしまうのな。

ページの取得はrequests、解析はlxmlを使う。

Webページの事前解析

ページのソースから、狙いの箇所を特定するようなキーワードを見つける。
あるいは、たとえばChromeなら、デベロッパーツールで探してもよい。
京急のページであれば、以下のように。

keikyuanalyze
手がかりは”div.unko-panel”。
これをもとにコードを書く。

抽出コード

stackoverflowを調べればサンプルコードなんかいくらでもあるよねー。

import lxml.html
import requests

def getKeikyuStatus():
    target_url = "http://unkou.keikyu.co.jp/"
    target_html = requests.get(target_url).text
    root = lxml.html.fromstring(target_html)

    divs = root.xpath("//div[contains(@class, 'unko-panel')]")
    for div in divs:
        unkouinfo = div.text_content().encode("UTF-8")

    return unkouinfo.strip()

requestsでwebページ取得。
lxmlで読み込んで、class “unko-panel”のdivタグを見つければよい。

[参考]slackへの投稿

ここはサラッと。
詳細はslackのサイトを見る。
前章の関数の戻り値を引数に取る関数。

def noticeSlack(keikyuStatus):
    url ="https://slack.com/api/chat.postMessage"
    msg = keikyuStatus + " #keikyu"

    payload_dic = {
        "token": "xoxb-xxxx-xxxx",
        "type": "message",
        "channel":"#general",
        "text":msg,
        "username":"keikyubot",
        "icon_emoji":":bird:",
        }

    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    r = requests.post(url, params=payload_dic, headers=headers)

    return r

[Python] wxPythonで、タイトルバーにアイコンを表示するには

Pocket

Pythonからpy2exeなどでWindowsアプリケーションを作成したときに、アイコンを設定することができる。
しかし、作成したアプリケーションがGUI版の場合、GUIタイトルバーのアイコンを設定するには、ちょっとしたテクニックが必要である。
py2exe等でアイコン設定済み、かつGUIはwxPythonで作成している前提で、その方法を示す。

サンプル

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
	(略)
		if os.path.exists("myWxApp.exe"):
    		self.SetIcon(wx.Icon("myWxApp.exe",wx.BITMAP_TYPE_ICO))

Frameクラスの初期化defの中で、上記のような記載を加える。
もちろんmyWxApp.exeは最終的なファイル名。

説明

py2exe等でiconファイルを設定するというのは、つまり実行ファイルに埋め込むということ。
上記のようにSetIconで自分自身の実行ファイルを参照すると、埋め込んでおいたアイコンファイルを読み取ることができる。

元ネタ
How to use py2exe icon_resources in wxPython application?

【参考】wxPython

http://ja.wikipedia.org/wiki/WxPython
wxPythonは、「wxPythonはPythonで記述されたクロスプラットフォームなウィジェット・ツールキットである。」
要するにPythonをGUIで動かすツールキット。OSをまたがって使用できる。

[Python] Sublime textのインストールと設定

Pocket

Pythonのエディタとして、長らくIDLEを使っていたけれども、Sublime textに巡り合って満足した。
導入方法について記す。

日曜プログラマのコードエディタ

俺みたいな日曜プログラマは間欠泉的にコードを書く。
つまり日常的にコードを書くわけではないので、文法やらなにやら、すぐに忘れてしまう。
こういう人々にとっては、コードを書くための支援や補助があるエディタは非常にありがたい。
となると、一番に候補に挙がるのはEclipseであるが、日曜プログラマはそんな重量級のIDEを使うほど必死でもない。
となると高機能なテキストエディタくらいがちょうど良いのである。
sublime textは、そんな要望にピッタリであった。

sublime textとは

「コードを書くための洗練されたテキストエディタ」だそうで。
追加機能はパッケージシステムで実現されていて、駆使すれば驚くようなことができる。
sublime textは$70であるが、お金を払わずとも使用はできる。
Windowsでも、Macでも使える。

インストール

http://www.sublimetext.com/3

上記からダウンロード、インストールすればよい。
2と3があり、3はベータの段階であるが、まあ3でよいでしょう。
ポータブルバージョンもあるのが嬉しい。
しかし、本体インストールだけでは単なるテキストエディタ。
続けてパッケージシステムを有効にして、パッケージをいくつかインストールする。
その前に。

書いたコードの実行はCtrl + B

そのまま。
コードを書くエディタにテキストエディタを選んだときの一番の欠点は、コードの実行である。
テキストエディタで書いて、ターミナル/コマンドプロンプトを開いて実行し、またエディタに戻って…というのが苦痛。
これが嫌で、かといって重量級IDEも嫌で、しょうがなくPython付属のIDE(?)であるIDLEをしばらく使っていた。
もちろん、テキストエディタでだって、コードを実行することもできる。
しかしそれには(俺にとっては)面倒な設定が必要なんだが、Sublime textならCtrl + Bだけで済む。もちろんpython等がPATHに入っている必要はあるけれども。
ではパッケージの話へ。

パッケージシステムの有効化

パッケージシステムを有効にするには、sublime textでコマンド実行する必要がある。
そこだけ聞くと面倒そうだが、意外に簡単。

ctrl+` と叩くか、View > Show Console。
現れた欄に https://packagecontrol.io/installation にあるコードを貼り付ける。

同サイトに以下の警告がある通り、必ずサイトからコードをコピーすること。

Warning: Please do not redistribute the install code via another website. It will change with every release. Instead, please link to this page.

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

さっそくパッケージをインストール。
Preference > Package Control > Install Package と進むか、Ctrl + Shift + P  と叩き、さらに”install”とタイプ、リターン。
インストール可能なパッケージが並ぶので、カーソルで選んでリターンを押すだけ。
どのパッケージをインストールするか。
最初は以下のページからザクザクインストールしたらよい。不要なら無効にできるしね。

パッケージ人気ランキング
https://packagecontrol.io/browse/popular

以下、パッケージの説明。

おすすめパッケージ

SublimeLinter
http://sublimelinter.readthedocs.org/en/latest/
Sublime​Linter-pep​8
https://packagecontrol.io/packages/SublimeLinter-pep8
SublimeLinterは書式をチェックしてくれる(Linter)もの。
追加で言語パッケージを入れる必要がある。pep8はPython用。

SideBarEnhancements
https://packagecontrol.io/packages/SideBarEnhancements
Sublime Textは、左側ペインにファイルのリストが表示される。ここでの操作を強化するパッケージ。

Theme-Soda
https://packagecontrol.io/packages/Theme%20-%20Soda
テーマですね。テーマはSublime text全体の見た目を、カラースキームはコード表示を決める。

BracketHighlighter
https://packagecontrol.io/packages/BracketHighlighter
カッコを強調表示。

SublimeCodeIntel
https://packagecontrol.io/packages/SublimeCodeIntel
コード補助だけど、ちょっと鬱陶しいかも。

Alignment
http://wbond.net/sublime_packages/alignment
イコールの場所を揃えてくれる。
以下はWindowsの日本語関係

ConvertToUTF8
https://packagecontrol.io/packages/ConvertToUTF8

IMESupport
https://packagecontrol.io/packages/IMESupport

No tags for this post.

[Python][Windows] Windows7への純正Pythonインストールメモ

Pocket

ActivePython入れたり純正Python入れたり訳わかんなくなるからメモ。

Pythonのインストール

https://www.python.org/ から2.xでも3.xでもダウンロード、インストール。
アップグレードの場合は、たぶん自分で古いバージョンをアンインストールした方がよい、と思う。
pythoninstallpathadd
インストール時設定は、pythonをpathに追加するところだけ変更した。

pipのインストール

不要ッ!
2.7.9以降、あるいは3.4以降なら最初っからインストールされている。
pip included with Python
実際、デフォルトの状態で以下の通り。

C:\Users\nobwak>python --version
Python 2.7.9

C:\Users\nobwak>pip list
pip (1.5.6)
setuptools (7.0)

ん?ちょっと古いような?

pip install -U pip

などとして最新版にした。

[Python] wxGladeでGUIのデザインを

Pocket

Python、Perl、Ruby、PHPなどのLight Languageは、俺みたいな素人プログラマでもじゃんじゃんコードを書けるところが素晴らしい。
さらにそのコードがGUIで動くようになるのなら、もっと素晴らしい。
wxGladeでそれができる。wxGladeでGUIを作ってみたので記す。

wxGladeとは

http://wxglade.sourceforge.net/index.php
wxPython向けのGUIデザイナーである。
wxPythonとはPythonのGUIツールキット。
また、GNOMEのGUIツールキットであるGladeが名前に入っている通り、wxGladeの設計思想はGladeに沿っている。

インストール

こちらからどうぞ。
以下の例ではWindowsを使っている。

最初の一歩

どんなGUIを作るにしても、まず最初にすべきことがある。

起動すると以下のような画面。
wxpyatstart
何のとっかかりもなく、いきなり途方に暮れるわけだが、慌てず騒がず、左上ウインドウのさらに左上にあるアイコンをクリック。
wxpyaddflame
そのままOK。
wxpyMyframe
wxpyaddframedone
なんか枠ができた。
wxpyframewin
そしてこちらを選んで、先ほどの枠に追加。
wxpaneladd
するとこのようなのっぺりした画面に。
basepanel01
あとは分かりやすいように名前を変更。
rootpanel
これで最初の一歩が終了。
ここから、作りたいGUIに合わせて作業をしていく。

作業の前に(日本語は使わないでおこう…)

超絶分かりやすいPythonにも弱点がある。
それは文字コードの扱い。
wxGladeで日本語を書き込むことはできるが、UTF-8なのかShift-JIS(CP932)なのかの扱いが大変に面倒である。
だから、GUI作成時のテキスト、注釈、ボタンは適当な英語で書いておき、実際の処理を書くときに日本語に変えるのがよいと思う。

画面の分割と配置

最終的に以下のようなGUIを作りたいとする。
wxpylast
このGUIは、まず画面を縦に三分割する。さらに1行目、3行目を横に三分割する。
分割にはパレット上の以下のツールで行う。
wxpybunkatsu
ざくざくと分割して以下のように。
wxpyseparate
以下のように便宜的に番号を振って、
wxpynumbers
①にはテキストを、②にはテキストの枠を、③にはボタン、④には横棒、⑤にはスペース、⑥、⑦にはボタンを置く。
wxpyzakkuri
ツリーはこんなかんじ。
wxpyhidarigawa
名前を変更し、空白(スペーサー)は適当に横に伸ばす。
あとは、経験上、各要素を以下のようにするといいかも。
wxpybityousei
wxpylast

書き出し

wxpyapp
Appのプロパティから、LanguageにPython、Output Pathでファイルを指定し、Generate Codeでコード生成。

以下が例。

#!/usr/bin/env python
# -*- coding: CP932 -*-
#
# generated by wxGlade 0.6.8 (standalone edition) on Sun Dec 28 07:13:39 2014
#

import wx

# begin wxGlade: dependencies
import gettext
# end wxGlade

# begin wxGlade: extracode
# end wxGlade


class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.panel_1 = wx.Panel(self, wx.ID_ANY)
        self.label_1 = wx.StaticText(self.panel_1, wx.ID_ANY, _("input : "))
        self.inputfile = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
        self.ChooseButton = wx.Button(self.panel_1, wx.ID_ANY, _("Choose"))
        self.static_line_1 = wx.StaticLine(self.panel_1, wx.ID_ANY)
        self.go = wx.Button(self.panel_1, wx.ID_ANY, _("Run"))
        self.exit = wx.Button(self.panel_1, wx.ID_ANY, _("Cancel"))

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_BUTTON, self.choosefile, self.ChooseButton)
        self.Bind(wx.EVT_BUTTON, self.goclicked, self.go)
        self.Bind(wx.EVT_BUTTON, self.exitclicked, self.exit)
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle(_("frame_1"))
        self.ChooseButton.SetToolTipString(_("choose a file "))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3.Add(self.label_1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_3.Add(self.inputfile, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_3.Add(self.ChooseButton, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 5)
        sizer_2.Add(self.static_line_1, 0, wx.EXPAND, 5)
        sizer_4.Add((200, 20), 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_4.Add(self.go, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_4.Add(self.exit, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
        self.panel_1.SetSizer(sizer_2)
        sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()
        # end wxGlade

    def choosefile(self, event):  # wxGlade: MyFrame.
        print "Event handler 'choosefile' not implemented!"
        event.Skip()

    def goclicked(self, event):  # wxGlade: MyFrame.
        print "Event handler 'goclicked' not implemented!"
        event.Skip()

    def exitclicked(self, event):  # wxGlade: MyFrame.
        print "Event handler 'exitclicked' not implemented!"
        event.Skip()

# end of class MyFrame
if __name__ == "__main__":
    gettext.install("app") # replace with the appropriate catalog name

    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_1 = MyFrame(None, wx.ID_ANY, "")
    app.SetTopWindow(frame_1)
    frame_1.Show()
    app.MainLoop()