Hatena::ブログ(Diary)

Memo

2013-06-15

[] 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

[][] Ruby から RiakCS にアクセスする

メモ。

aws-sdk を使ったら行けた。

# -*- 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

*1:自分の Ruby 力が低いのも大きい

2013-06-01

[][] 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 ブランチに取り込まれた。

Merge pull request #138 from heavenshell/fix_deprecation_warning ? 622331a ? davidhalter/jedi-vim ? GitHub


警告自体は 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 CS を使ってみる

Riak が動いたので、Riak CS も試してみる。

Vagrant で作った CentOS 上に yum を使って Riak CS に必要なパッケージはインストール済み。


Riak CSHTTP ポートに 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},

Riak, Riak CS再起動

$ 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 keysecret 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

RiakCSでプライベートストレージを作ろう! - 偏った言語信者の垂れ流し

An Introduction to boto’s S3 interface — boto v2.9.5

2013-05-28

[] 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

ちゃんとポートフォワードしてるはずなのに…。

と困ってたら @ さんに教えて頂いた。

ありがとうございます!!


/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

参考文献

Riak

Basho Japan Blog ? MacにRiak-1.3.1をインストールする

Riak を Python で使う - Ian Lewis

ひとりでやるRiak Advent Calendar 2012 day1 - 入門 - kuenishi's blog

*1:あとでちゃんとやる予定

2013-05-11

[] 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

[] 検索時のハイライト

/ とかで検索時にデフォルトじゃハイライトされていて、どの行にいまカーソルがあるのか分かりにくい。

/ とか * とかの検索の場合は <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 の場合下線が置換対象に表示されるようになる。

# これ検索の時も出来ないかなー。


なおスパルタンな方法は以下の通り。