2013-06-15
■[Python] Flask の Extension の Python3 対応状況
Flask がめでたく Python3.3 をサポートしたので、Flask に依存している Flask-Extension の Python3 対応状況が気になったので調べてみた。
#!/usr/bin/env python # -*- coding: utf-8 -*- import pprint import requests from bs4 import BeautifulSoup PYPI = 'https://pypi.python.org{0}' list_page = requests.get(PYPI.format('pypi?%3Aaction=search&term=flask&submit=search')) soup = BeautifulSoup(list_page.content) items = soup.find_all( lambda tag: tag.name == 'td' and tag.find('a') != None ) urls = [v.contents[0].get('href') for v in items] results = [] for url in urls: r = requests.get(PYPI.format(url)) package_page = BeautifulSoup(r.content) logo = package_page.find_all(id='logo')[0].get('src') if logo == '/python-3.png': results.append(url) pprint.pprint(results)
PyPi の検索で Flask と入力して出てきた結果一覧のリンクの中で Python3 のロゴが出ているものだけを抽出した。
# PyPi にあまり負荷をかけたくないから直列でアクセスしている
# そのため遅い
['/pypi/Flask/0.10.1', '/pypi/Flask-BasicAuth/0.2.0', '/pypi/Flask-Classy/0.6.3', '/pypi/Flask-MakeStatic/0.2.0', '/pypi/mixer/0.5.0', '/pypi/errormator-client/0.5.12', '/pypi/mimerender/0.5.3', '/pypi/python-social-auth/0.1.7', '/pypi/Tornado-Restless/0.1.0', '/pypi/Attest/0.5.3', '/pypi/Attest-latest/0.6.1dev-20130603', '/pypi/bootstrapper/0.1.5', '/pypi/celery/3.0.19', '/pypi/cookies/1.2.1', '/pypi/crochet/0.7.0', '/pypi/disco-dop/0.2', '/pypi/err/2.0.0-beta', '/pypi/Gears/0.6', '/pypi/healthy/0.1.2', '/pypi/meinheld/0.5.5', '/pypi/natrix/0.0.1', '/pypi/py3support/0.1.1', '/pypi/pyforms/0.1', '/pypi/pyramid_debugtoolbar/1.0.6', '/pypi/pyrc/0.6.4', '/pypi/raven/3.3.7', '/pypi/statsd-client/1.0.4', '/pypi/Tornado-Backbone/0.1.0', '/pypi/url_shortener/0.5.18', '/pypi/WSME/0.5b2']
直接 Flask と関係ないものも入ってるけど…。
Flask が Python3 対応をちゃんとリリースしてからまだ日が浅いのでしばらくしたら対応されるかと思う。
2013-06-06
■[Riak][Ruby] Ruby から RiakCS にアクセスする
メモ。
# -*- encoding: utf-8 -*- require 'logger' require 'aws-sdk' configs = { access_key_id: 'C_AHU4UXUQE9CBDSY8WX', secret_access_key: 'GR63vRcdenI1P99LPD8_ucE_RZhf9lpXwlyVxA==', s3_endpoin: 'localhost', proxy_uri: 'http://localhost:9090', use_ssl: false, # logger: Logger.new($stdout), # log_level: 'debug', } AWS::config(configs) connection = AWS::S3.new buckets = connection.buckets['bucket_name'] # List all items = [] buckets.objects.each do |obj| p obj.key items.push(obj.key) end # Get item item = buckets.objects[items[0]] File.open('./test.txt', 'wb') do |file| item.read do |chunk| file.write(chunk) end end
Proxy の書き方が分からなくて困った…。
URI 形式で書けば行けた。
Boto みたいに詳細なドキュメントが見つけられなくて困った*1。
結局 Fluent の S3 プラグインの実装を眺めて初めて Proxy の設定の仕方が分かった。
fluent-plugin-s3/lib/fluent/plugin/out_s3.rb at master ? fluent/fluent-plugin-s3 ? GitHub
2013-06-01
■[Vim][Python] jedi.vim に Pull Request した
jedi.vim をアップデートしたら以下の様な警告が表示された。
jedi-vim/jedi/jedi/api.py:209: DeprecationWarning: Use completions instead.
warnings.warn("Use completions instead.", DeprecationWarning)
補完自体は出来るが警告が気になったのでソースを追ってみた。
この警告自体は Jedi 自体が出している。
どうやら jedi.vim が依然古い API を使っているからのようだ。
なので、古いのを使わなくして新しい API に書き換えたのを Pull Request したら dev ブランチに取り込まれた。
警告自体は Python 2.6 な環境のみ出た。これが Python 2.7 な環境だと警告が出ない。
# 因になんで Python 2.7 で出ないかというと Python 2.7 から DeprecationWarning はデフォルトで無視されるようになったから
27.6. warnings ? 警告の制御 — Python 2.7ja1 documentation
Python 2.7 だと警告は出ないとはいえ Deprecate な API を使ってる事には違いがないので Pull Request を出した。
Deprecate な API から新しい API 呼び出してるのでそのオーバヘッドも出るし。
これを書いてる時点では master ブランチにはまだ取り込まれてないので、dev ブランチを使うと新しい API を使うようになって、DeprecationWarning を実行しなくなる。
2013-05-29
■[Riak][Python] Riak CS を使ってみる
Riak が動いたので、Riak CS も試してみる。
Vagrant で作った CentOS 上に yum を使って Riak CS に必要なパッケージはインストール済み。
Riak CS は HTTP ポートに 8080 を使っているので、Virtual Box にポートフォワードさせる。
Vagrantfile に以下を追加。
config.vm.network :forwarded_port, guest: 8080, host: 9090, auto_correct: true # riak-cs http
Vagrant reload で仮想マシンを再起動をし、8080 を 9090 にポートフォワードした。
設定ファイルの変更を行う。
Riak CS を使うために Riak の設定ファイルを書き換えた。
{riak_core, [ のセクションに以下を追加。
{default_bucket_props, [{allow_mult, true}]},
続いて {riak_kv, [ のセクションに以下を追加。
{add_paths, ["/usr/lib64/riak-cs/lib/riak_cs-1.3.1/ebin"]},
{storage_backend, riak_cs_kv_multi_backend},
{multi_backend_prefix_list, [{<<"0b:">>, be_blocks}]},
{multi_backend_default, be_default},
{multi_backend, [
{be_default, riak_kv_eleveldb_backend, [
{max_open_files, 50},
{data_root, "/var/lib/riak/leveldb"}
]},
{be_blocks, riak_kv_bitcask_backend, [
{data_root, "/var/lib/riak/bitcask"}
]}
]},
続いて /etc/riak-cs/app.config で以下のように変更。
{anonymous_user_creation, false},
$ sudo /etc/init.d/riak stop $ sudo /etc/init.d/riak start $ sudo /etc/init.d/riak-cs stop $ sudo /etc/init.d/riak-cs start
Riak, Riak CS が正しく動作しているか確認。
$ riak ping Attempting to restart script through sudo -H -u riak pong $ riak-cs ping pong
Riak CS を使うには Access key と secret key が必要になるのでユーザを登録する。
折角なのでホストマシンからポートフォワードして作成してみた。
$ curl -H 'Content-Type: application/json' -X POST http://localhost:9090/riak-cs/user --data '{"email":"foo@example.com", "name":"foo"}'
{"email":"foo@example.com","display_name":"foo","name":"foo","key_id":"C_AHU4UXUQE9CBDSY8WX","key_secret":"GR63vRcdenI1P99LPD8_ucE_RZhf9lpXwlyVxA==","id":"84631c232d0e7cb046292d31bcc89b53d0b18f7ee387bda02cf77c7bee6524d8","status":"enabled"}
続いて確認用に s3cmd を入れてみる(こっちは仮想マシンの方に入れてみた)。
$ pip install s3cmd $ s3cmd --configure Access key and Secret key are your identifiers for Amazon S3 Access Key: C_AHU4UXUQE9CBDSY8WX Secret Key: GR63vRcdenI1P99LPD8_ucE_RZhf9lpXwlyVxA== Encryption password: test Path to GPG program [/usr/bin/gpg]: Use HTTPS protocol [No]: HTTP Proxy server name: 127.0.0.1 HTTP Proxy server port [3128]: 8080 New settings: Access Key: C_AHU4UXUQE9CBDSY8WX Secret Key: GR63vRcdenI1P99LPD8_ucE_RZhf9lpXwlyVxA== Encryption password: test Path to GPG program: /usr/bin/gpg Use HTTPS protocol: False HTTP Proxy server name: 127.0.0.1 HTTP Proxy server port: 8080
上手く動くか確認。
$ s3cmd ls
バケットとか何も作ってないので何も表示されない。
仮想マシンに Riak の 動作を確認するために Python スクリプトがあったので試しにそれを突っ込んでみる。
$ s3cmd mb s3://test Bucket 's3://test/' created $ s3cmd ls 2013-05-29 18:40 s3://test $ s3cmd put sample.py s3://test WARNING: Module python-magic is not available. Guessing MIME types based on file extensions. sample.py -> s3://test/sample.py [1 of 1] 495 of 495 100% in 0s 6.78 kB/s done
警告が出たのは .py なんてファイルを突っ込んだからだろう。
続いてホストマシンから先ほど突っ込んだファイルを取得できるかテストしてみる。
今回は Python の boto を使う。
$ pip install boto
#!/usr/bin/env python # -*- coding: utf-8 -*- from boto import connect_s3 from boto.s3.key import Key from boto.s3.connection import OrdinaryCallingFormat connect = connect_s3( aws_access_key_id='C_AHU4UXUQE9CBDSY8WX', aws_secret_access_key='GR63vRcdenI1P99LPD8_ucE_RZhf9lpXwlyVxA==', host='localhost', proxy='localhost', proxy_port=9090, calling_format=OrdinaryCallingFormat(), debug=2, # show debug info is_secure=False, ) bucket = connect.get_bucket('test') k = Key(bucket) k.key = 'sample.py' k.get_contents_to_filename('./foo.py')
これでホストマシン上に仮想マシンから突っ込んだ sample.py を foo.py として保存できた。
お手軽!
# debug=2 とやってるからデバッグ情報も見る事ができる
今度はホストマシンからファイルを突っ込んでみる。
$ echo こんにちはこんにちは > text.txt
#!/usr/bin/env python # -*- coding: utf-8 -*- from boto import connect_s3 from boto.s3.key import Key from boto.s3.connection import OrdinaryCallingFormat connect = connect_s3( aws_access_key_id='C_AHU4UXUQE9CBDSY8WX', aws_secret_access_key='GR63vRcdenI1P99LPD8_ucE_RZhf9lpXwlyVxA==', host='localhost', proxy='localhost', proxy_port=9090, calling_format=OrdinaryCallingFormat(), debug=2, # show debug info is_secure=False, ) bucket = connect.get_bucket('test') k = Key(bucket) k.key = 'test.txt' ret = k.set_contents_from_filename('./test.txt') print ret
仮想マシン上のコンソールで以下のコマンドを実行。
$ s3cmd get s3://test/test.txt s3://test/test.txt -> ./test.txt [1 of 1] 31 of 31 100% in 0s 4.16 kB/s done $ cat test.txt こんにちはこんにちは
ちゃんと取得できた。
AmazonS3 互換で既存のライブラリを使えるのがお手軽で素晴らしい。
参考文献
【緊急】 Riak Cloud Storage が OSS になりました【速報】 - kuenishi's blog
2013-05-28
■[Riak] Riak を使ってみる
ここ数日 Riak について調べていたのでメモ。
因にゴールが Riak CS を使って分散ストレージを使う事。
まずは Riak のセットアップ。
手元の Mac に入れてみる。
Basho Japan Blog ? MacにRiak-1.3.1をインストールする を参照。
#!/usr/bin/env python # -*- coding: utf-8 -*- client = riak.RiakClient() bucket = client.bucket('mybucket') obj = bucket.new('key', data={ 'spam': 'foo', 'eggs': 'bar' }) obj.store() obj = bucket.get('key') print obj.get_data()
こんなんを書いて実行して
{'eggs': 'bar', 'spam': 'foo'}
が表示された。
手元でも良いけど Linux で構築したいので Vagrant の出番。
Vagrant.configure("2") do |config| config.vm.box = "centos" config.vm.network :forwarded_port, guest: 8098, host: 9098, auto_correct: true # riak http config.vm.network :forwarded_port, guest: 8087, host: 9087, auto_correct: true # riak pb config.vm.network :forwarded_port, guest: 9999, host: 8765, auto_correct: true # riak pb end
こんな Vagrantfile を作って、vagrant up を実行。
# Fabric で自分の Vagrant 環境を構築するために、Sahara を入れて環境作っては怖しを繰り返してた
# 以下コマンドで書いてるけど、全て Fabric 化済み
# プロダクションで使う事になったら Vagrant じゃなくて職場の仮想サーバの上に構築するので、Chef で構築予定
# 今は調査してる段階だし、個人環境なので Fabric を使ってる
Riak, Riak CS, Stanchion のインストールは yum のリポジトリから実施。
$ sudo yum install http://yum.basho.com/gpg/basho-release-6-1.noarch.rpm $ sudo yum install riak $ sudo yum install riak-cs $ sudo yum install stanchion $ sudo yum install riak-cs-control $ wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm $ rpm -Uvh epel-release-6-8.noarch.rpm $ sudo yum install protobuf $ sudo yum install protobuf-devel
Python の riak クライアントに Protocol Buffers のライブラリが必要なのでインストールする。
めんどくさいので iptables とかはオフ*1。当然 SELinux も Disabled にする(vagrant up したら Disabled になってた)。
$ sudo /etc/init.d/iptables stop
Riak の設定ファイルとかは Configuring Riak for CS を参考に追加。
$ sudo /etc/init.d/riak start $ sudo /etc/init.d/riak-cs start $ sudo /etc/init.d/stanchion start
まずは Riak が起動してるか VirtualBox のマシンからチェック。
$ curl -v http://localhost:8098/ping * About to connect() to localhost port 8098 (#0) * Trying ::1... Connection refused * Trying 127.0.0.1... connected * Connected to localhost (127.0.0.1) port 8098 (#0) > GET /ping HTTP/1.1 > User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.13.1.0 zlib/1.2.3 libidn/1.18 libssh2/1.2.2 > Host: localhost:8098 > Accept: */* > < HTTP/1.1 200 OK < Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue) < Date: Tue, 28 May 2013 10:24:22 GMT < Content-Type: text/html < Content-Length: 2 < * Connection #0 to host localhost left intact * Closing connection #0 OK
VirtualBox のホストのマシンからもチェックしようとしたら以下の様な応答になった。
$ curl -v http://localhost:9098/ping * About to connect() to localhost port 9098 (#0) * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 9098 (#0) > GET /ping HTTP/1.1 > User-Agent: curl/7.29.0 > Host: localhost:9098 > Accept: */* > * Empty reply from server * Connection #0 to host localhost left intact curl: (52) Empty reply from server
ちゃんとポートフォワードしてるはずなのに…。
と困ってたら @voluntas さんに教えて頂いた。
ありがとうございます!!
@heavenshell NAT で 192.168.33.10 とかにして、riak 側を 127.0.0.1 ではなく 0.0.0.0 で上げれば Mac 側から 192.168.33.10/ とかで繋がるはずですけどねぇ。。なんだろう。
/etc/riak/app.config で 127.0.0.1 になってるのを全て 0.0.0.0 に変更し、Riak を再起動したら正しく動いた!
ということでホストマシンからもアクセスできるようになった。
原因は 127.0.0.1 だと Riak をホストしてるマシンからしか見えないよう。
app.configを見ればわかると思うが、このままだとデフォルトのポートはすべてループバックアドレスをlistenしてしまう。そのためローカルマシンからしかアクセスすることができない。これを外からでも見えるようにするためには、 etc/app.config と etc/vm.args に 127.0.0.1 と書いてあるところをすべてそのマシンのIPアドレスで書き換えること。 0.0.0.0 にしてもよいところとしてはいけないところに分かれているので、基本的にはそのネットワークで定義されているIPアドレスにしなければならない。
ちなみにIPv6は1.3以降のバージョンから動く、かもしれない。
ひとりでやるRiak Advent Calendar 2012 day1 - 入門 - kuenishi's blog
参考文献
*1:あとでちゃんとやる予定
2013-05-11
■[Python] Celery を使ってみる
昔ちょっと Celery を試した事があったが、ジョブキューなのが必要になったので再入門してみた。
WAF には Flask を使っている。
Celery には Flask の Extension があるが、Celery3.0 になってから非推奨になっており、Celery 本体の API を使う事が推奨されている。
Flask-Celery には Flask-Script と連動できたが、自分で管理する必要がある。
extensions.py
# -*- coding: utf-8 -*- import project.configs.celeryconfig as config from celery import Celery celery = Celery('SampleTask') celery.config_from_object(config) __all__ = ['celery']
tasks/sample.py
# -*- coding: utf-8 -*- from celery.contrib.methods import task_method from project.extensions import celery class SampleTask(object): def __init__(self): pass @celery.task(filter=task_method, name='SampleTask.run') def run(self, task_data): """ Interface for Celery task. :param task_data: """ return 'task {0}'.format(task_data)
views.py
# -*- coding: utf-8 -*- from flask import Blueprint, current_app, request, jsonify from celery.task.control import revoke from project.tasks.sample import SampleTask app = Blueprint('task', __name__, url_prefix='/task') @app.route('/', strict_slashes=False, methods=['POST']) def compile(): logger = current_app.logger form = request.form['data'] t = SampleTask() result = t.run.delay(form) logger.info('Add task({0})'.format(result.id)) return jsonify(response={'taskid': result.id}) @app.route('/<task_id>', strict_slashes=False, methods=['GET']) def compile_result(task_id): logger = current_app.logger t = SampleTask() result = t.run.AsyncResult(task_id) if result.status == 'PENDING': logger.info('task id({0}) not exists'.format(task_id)) return jsonify(response={'result': None}) response = result.get() revoke(task_id, terminate=True) return jsonify(response={'result': response})
ワーカーを起動する。
$ celery -A project.tasks.sample worker -l info -E
シェルで直接起動してるが、プロダクション用には Supervisor で管理しているので、Supervisor の conf ファイルで起動コマンドを記述する。
ワーカーはサンプルとかチュートリアルは大抵関数ベースで書かれてるけど、クラスベースでのやり方を知りたかったので書いてみた。
クラスベースではただの @celrey.task だけではだめで、@celery.task(filter=task_method) としなければ動作しない。
関数ベースのだと簡単に動いたのに、クラスベースではエラーが出て動かなくてハマった。
2013-04-30
■[Vim] 検索時のハイライト
/ とかで検索時にデフォルトじゃハイライトされていて、どの行にいまカーソルがあるのか分かりにくい。
/ とか * とかの検索の場合は <S-v> でビジュアルモードで現在行を視認するという方法もある。
これが、:%s/foo/bar/gc の様な場合で、foo が沢山ある場合、今どの foo が置換対象なのか分かりづらかった。
置換時に set cursorline とか出来ないんかなーと思ったら、highlight でなんとかなった。
highlight Search cterm=bold gui=bold ctermfg=Yellow ctermbg=none guifg=yellow highlight IncSearch cterm=bold,underline gui=bold,underline ctermfg=Yellow ctermbg=none
これで、CUI の場合下線が置換対象に表示されるようになる。
# これ検索の時も出来ないかなー。
なおスパルタンな方法は以下の通り。
@heavenshell /pattern/ で組んだ後 v//d して不要なものが入ってないか目視確認して、undoして :%s//replacement/g でしょ。
2013-04-19 19:07:11 via web to @heavenshell
