らっちゃいブログ

日々の学びと気づきを発信するブログ

Macにipコマンドをインストールしたのでメモ

普段 Ubuntu マシンをメインに据えて Mac をサブマシンとして開発しているわけですが、Mac に ip コマンドがないのが不便だったのでインストールしてみました。

インストール

今回は homebrew でインストールしました。

brew tap brona/iproute2mac
brew install iproute2mac

確認してみる。

$ ip
Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
       ip -V
where  OBJECT := { link | addr | route | neigh }
       OPTIONS := { -4 | -6 }

iproute2mac
Homepage: https://github.com/brona/iproute2mac
This is CLI wrapper for basic network utilities on Mac OS X inspired with iproute2 on Linux systems.
Provided functionality is limited and command output is not fully compatible with iproute2.
For advanced usage use netstat, ifconfig, ndp, arp, route and networksetup directly.

インストールできてそうです。

ip コマンドで IP アドレスを確認してみます。

$ ip add
$ ip a
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet6 ::1/128
        inet 127.0.0.1/8 lo0
        inet6 fe80::1/64 scopeid 0x1
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        ether xx:xx:xx:xx:xx:xx
        inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scopeid 0x4
        inet xx.xx.xx.xx/24 brd xx.xx.xx.255 en0

無事動いてますね。これで ubuntumac でコマンドが違う問題が解決されました。ばんざい。

日本橋でぜいたく丼っぽい中落ち丼を食べてきた

お店

今回のお店はこちら。先日できたばかりの東京日本橋タワーB1Fにある『ま石』さんです。

f:id:racchai:20160527120552j:plain:w400

店構えが高そうなので軽くひよりました。いや、メニュー見ると実際高いんですが。。

f:id:racchai:20160527120941j:plain:w400

一部の丼メニューだけはぎりぎり手が届きそうだということで、いざ入店!

お昼時にもかかわらず、待ちどころか結構空いてました。みなさん敬遠されてるんですかね。

注文

カウンターのど真ん中に通されて着席。メニューは見ません。実質中落ち丼と上海鮮丼の二択です。これ以外は高くてダメ。。

  • 中落ち丼 1,200円(税抜き)
  • 海鮮丼 1,600円(税抜き)

今回は中落ち丼を注文することに決めてたので、さっそく注文しました。お客さんがほとんどいないこともあり、注文したらすぐ作ってもらえました。

食す

はい、どーん。

f:id:racchai:20160526222557j:plain:w400

ぱっと見た感じ、ぜいたく丼っぽくないですか?鯛の切り身(ゴマダレ)もあります。

ぜいたく丼を知らない方はこちらをどうぞ。

racchai.hatenablog.com

つじ半と違うのは、ご飯の追加ができない点でしょうか。

『あとでお出汁をおかけしますので、切り身とご飯を少しずつ残しておいてください』

とのことでした。まあそういうもんですよね。それではいただきます。

まずはお醤油にわさびを溶かして、上から余すことなく流し込みます。そして中落ちの塊を崩して、一口。

ふわとろだ!

うまい。ご飯は酢飯なんですね。やっぱり海鮮には酢飯が合うなあ。そして大量にかけられた白ゴマがなんともいい風味です。

個人的にはネギはなくてよかったですね。嫌いではないですがちょっと多い。

鯛の切り身もいただいてみると、ゴマダレが濃厚でご飯に合います。なんならちょっと濃すぎるくらいの味付けでした。すごくおいしい。これくらいパンチがある方が好みなんですよね。

〆る

量はそれほどないので、無心で食べていたら一瞬で〆となりました。

『出汁をください』

f:id:racchai:20160526222632j:plain:w400

出汁が入りました。つじ半とは違い、透き通るような出汁でした。上品ですね。

一口食べてみると・・あれ?

おいしいんですけど。。酢飯と出汁がそんなに合ってないような気が。。

出汁をかけるなら普通のご飯の方が好きかもしれない。

まとめ

非常においしい丼でありましたが、〆だけが少し残念でした。酢飯でないご飯を追加しての〆ができれば、完璧でしたね。

お値段はそこそこ張りますが、『つじ半に行きたいけど混み過ぎ!』というときにはちょうどよい選択肢かもしれませんね。

それでは今回のレポートはこれで以上です。来週は何食べようかなー。

【Python】いつまでprintデバッグで消耗してるの?

Python を初めて間もない頃、自分も print デバッグしてました。効率の悪さを認識しつつも、IDEを導入してデバッグする方法を調べてセッティングして、という手順が面倒でずっと放置してました。

// 普段は vim で開発してます

そうこうしてたら print デバッグではどうにもならないバグにぶち当たり、仕方なくデバッグポイントを置く方法を調べたわけです。するとどうでしょう。

ソースコード中に以下の一文を入れるだけではないですか。

import pdb; pdb.set_trace()

たったこれだけで、上の一文を挿入した行で処理が停止し、コンソール上でステップ実行が出来るようになります。最高かよ。

個人的にですが、デバッガー起動中によく使うコマンドとしては以下です。

コマンド 説明
s(tep) ステップイン
n(ext) ステップオーバー
r(eturn) ステップアウト
l(ist) 現在行の前後のソースコードを表示
a(rgs) 現在いる関数の引数を表示
p プリント
c(ont(inue)) 次のブレイクポイントまで実行

それでは簡単に試してみましょう。

今回は実行時の引数を print するだけの簡単なスクリプトを用意しました。main 関数実行前にブレイクポイントを置いています。

$ cat > /tmp/debug.py <<EOF
#!/usr/bin/env python

import sys

def log(args):
    print args

def main(args):
    log(args)

import pdb;pdb.set_trace()
main(sys.argv)
EOF

これを普通に実行するだけで・・

$ python debug.py
> /tmp/debug.py(12)<module>()
-> main(sys.argv)

main 関数の実行前で停止してくれました。念のため、実際の停止位置を l(ist) コマンドで確認してみます。

(Pdb) l
  7  
  8     def main(args):
  9         log(args)
 10  
 11     import pdb;pdb.set_trace()
 12  -> main(sys.argv)
[EOF]

はい、ばっちり main 関数で止まっています。それではステップイン!

(Pdb) s
--Call--
> /tmp/debug.py(8)main()
-> def main(args):
(Pdb) l
  3     import sys
  4  
  5     def log(args):
  6         print args
  7  
  8  -> def main(args):
  9         log(args)
 10  
 11     import pdb;pdb.set_trace()
 12     main(sys.argv)
[EOF]

main 関数内に入って行きました。せっかくなので引数の値を確認してみます。

(Pdb) a
args = ['/tmp/debug.py']

ちゃんと引数が渡ってきていることがわかりますね。次は p コマンドで引数の型を確認してみます。

(Pdb) p type(args)
<type 'list'>

list です。まあ見ればわかりますか。引数の中身が見れたら満足したので、continue コマンドで残りの処理を一気に流してしまいましょう。

(Pdb) c
['/tmp/debug.py']

無事引数が標準出力に表示されました。簡単ですね。

pdb の紹介は以上です。それではみなさんよいデバッグライフを!

合わせて読みたい

racchai.hatenablog.com

racchai.hatenablog.com

racchai.hatenablog.com

AtlassianがBitbucket Pipelinesを発表!さっそく試してみた

ここまでのお話。

racchai.hatenablog.com

待ちに待った招待メールが届きました。すぐでしたね。

f:id:racchai:20160527164349p:plain

まずは [Bitbucket Pipelines add-on] をインストールする必要があるそうです。

f:id:racchai:20160527164634p:plain

すべてのリポジトリで有効化するなら、チームアカウントではなく自分のアカウントに Grant access せよとのこと。[Select account] をクリックして、そのようにしました。

f:id:racchai:20160527165119p:plain

おお!なにやら有効化されたっぽいですね。さっそく適当にプロジェクトを開いてみると・・

f:id:racchai:20160527165636p:plain

Pipeline リンクが追加されている!クリックしてみると、まずはセットアップせよとのこと。

f:id:racchai:20160527165901p:plain

[Setup up Pipelines] をクリック。

f:id:racchai:20160528212308p:plain

ふむふむ。[Enable pipelines] にチェックをいれてbitbucket-pipelines.yml を配置するだけってことですね。

言語毎に bitbucket-pipelines.yml のサンプルが用意されているのですが、今回はPythonのサンプルで試してみます。以下をコピペしてプロジェクトルート以下に作成し、コミット&プッシュ!

# You can use a Docker image from Docker Hub or your own container registry
image: python:3.5.1
   
pipelines:
  default:
    - step:
        script:
          - pip install -U tox
          - pip --version
          - tox --version

Bitbucketの画面を見てみると、プッシュを検知してタスクが開始されていました。

f:id:racchai:20160528213454p:plain

タスクを開いてみると、ちょうどタスクが終了したところでした。

f:id:racchai:20160528213555p:plain

スクリプトの実行毎に結果を開閉できる形式なのが地味にうれしい。Jenkins だとただただログが大量に出力されるだけなので、どのコマンドで失敗したのかを追うのが大変なんですよね(あるある)

サンプルが動いたので、次は実際のプロジェクト(進行中)でテストを実行してみることにします。

内容は詳しく解説しませんが、やりたいことを script に書いてプッシュ。(叩くコマンドで多少のレガシー感を感じさせますね)

image: python:2.7.11

pipelines:
    default:
        - step:
            script:
                - pip install virtualenv
                - virtualenv venv
                - source venv/bin/activate
                - pip install -r requirements.txt
                - python manage.py test

結果はこちら。

f:id:racchai:20160528221041p:plain

思いがけず自動テスト完成しました。手元のMacで実行するとすごい時間かかるし、マシンが熱くなるのでなかなか実行できないんですよね。

おかげでプッシュの度にテストを走らせられます。本当にうれしい。ありがとうAtlassian!

AtlassianがBitbucket Pipelinesを発表!さっそく申し込んでみた

Atlassianが先日 Bitbucket Pipelines を発表したそうですね。

これで Bitbucket へのプッシュをトリガーにして自動デプロイのようなことができるようになるのでしょうか?

気になるので使ってみることにしました。

Get Bitbucket Pipelines』へアクセスしてみると、こんな画面が。

f:id:racchai:20160527084504p:plain

ベータ版の利用申し込みが必要なんですね。では申し込んじゃいます。[Sign up for beta] をクリック。

f:id:racchai:20160525232059p:plain

メールアドレスを求められました。とりあえず Bitbucket のアカウントで使ってるメールアドレスを入力してみます。すると、このようなメールが送られてきました。

f:id:racchai:20160525230448p:plain

意訳すると "waiting list" に入ったから Gmail 開いて正座して待っとけってことか。即時利用開始じゃないのかよ!

ということでいったん待ちです。招待メールが届いたら続きをレポートしようと思います。

追記

メールが届いたのでレポート書きました。

racchai.hatenablog.com

Django REST frameworkでAPIにアクセス権を実装する方法

Django REST framework シリーズです。今回はアクセス権のお話をします。

Django REST framework を使ったことがないという方はこちらをどうぞ。

racchai.hatenablog.com

はじめに

API を実装する上で欠かせないのが、アクセス権の管理ですね。API 毎に実行可能かどうかをチェックする処理を入れるのは大変ですし、対応漏れも起きやすいです。かといって、自前で共通化するのも大変ですね。

Django REST framework では permission という概念でAPI毎にアクセス権を設定できるようになっていますので、本記事ではよくあるアクセス権を例に挙げて実装方法について紹介してみようと思います。

具体的な解説に入る前に、サンプルのAPIを作っておきます。

api.py

from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

class SampleView(GenericAPIView):
    permission_classes = ()

    def get(self, request, format=None):
        return Response()

urls.py に以下を追加。

url(r'^sample', SampleView.as_view()),

SampleView に見慣れない permission_classes というフィールドが登場しましたが、Django REST framework ではここに Permission クラスを設定することでアクセス権を設定するようになります。

認証済みの場合のみアクセスさせたい

お決まりのやつですね。認証済みかどうかを検証するパーミッションについては、 Django REST Framework にて標準で用意されている IsAuthenticated がありますので、こちらを使うだけです。

from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

class SampleView(GenericAPIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        return Response()

permission_classes に IsAuthenticated を指定しました。これで認証済みでないと実行できないAPIとなります。

管理者のみアクセス可能

これもよくあるパターンですね。今回は特定のメールアドレス(admin@racchai.com)であれば管理者として判定するパーミッションを作成してみます。

作り方は簡単で、rest_framework.permissions.BasePermission を継承したクラスにて has_permission 関数を定義するだけです。has_permission 内でアクセス可能な条件を設定してあげれば、それだけでパーミッションクラスの完成となります。

from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.permissions import BasePermission 

class IsAdmin(BasePermission):
    def has_permission(self, request, view):
        return request.user and request.user.email == 'admin@racchai.com'

class SampleView(GenericAPIView):
    permission_classes = (IsAdmin,)

    def get(self, request, format=None):
        return Response()

IsAdmin パーミッションを作成し、それを SampleView に設定しました。たったこれだけで、管理者しかアクセスできないAPIとなりました。

管理者のみ変更可能でそれ以外は閲覧のみさせたい

さきほど作成した IsAdmin パーミッションをさらに発展させてやるだけで実現できますね。新しいパーミッションIsAdminOrReadOnly として作成します。

from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.permissions import BasePermission, SAFE_METHODS

class IsAdmin(BasePermission):
    def has_permission(self, request, view):
        return request.user and request.user.email == 'admin@racchai.com'

class IsAdminOrReadOnly(BasePermission):
    def has_permission(self, request, view):
        return request.method in SAFE_METHODS or IsAdmin().has_permission(request, view)

class SampleView(GenericAPIView):
    permission_classes = (IsAdminOrReadOnly,)

    def get(self, request, format=None):
        return Response()

    def post(self, request, format=None):
        return Response()

閲覧かどうかは、HTTP メソッドの種類で判別します。フレームワークの方で SAFE_METHODS(GET, HEAD, OPTIONS) が定義されているので、リクエストメソッドがそのどれかであれば True を返します。SAFE_METHODSでない場合は、IsAdmin パーミッションを評価することで実行可能かを判定するようになっています。

まとめ

簡単すぎてつまらない内容だったかもしれませんね。本当はパーミッションの仕組みでオブジェクトベースのアクセス権を設定することもできるのですが、長くなりそうなのでそれはまた別な機会にご紹介することにします。

それでは今回はこのへんで!

喉が痛いときはヴィックス一択でしょ。異論は認めない

朝起きたら風邪っぽくて喉が痛かったので、朝一でヴィックスをキメました。

イソジンでうがいとか別な薬飲んでも全く効かないけど、ヴィックスは即効性があってよく効くのでいつもお世話になってます。ただののど飴だと思われるかもしれませんが、医薬部外品とは思えない効果なので使ったことがない方はぜひ一度お試しください。

レモンフレーバーがおなじみ(?)ですが、最近は着色料などを気にしてレギュラータイプも買うようになりました。

ヴィックスとユンケル黄帝液があればもう風邪なんて怖くないですね!