taisablog

taisa's engineer blog

「 投稿者アーカイブ:taisa831 」 一覧

Python Bottleのソースを読む プラグイン編

2016/12/05   -Python
 ,

Pythonの軽量WebフレームワークBottleのソースを読む プラグイン編Bottleを触ってみると通常のWebフレームワークには用意されているであろう機能がなかったりします。これはマイクロフレームワークであるが故であり、すべてがそろってない状態がむしろ正しい状態と言えます。Bottleではそういったものを補うためにプラグインが用意されていてある程度の機能はそちらでまかなうことができます。また、Plugin Development Guide を参考にしてプラグインを自作することも可能です。 Class Hierarchy plugin用クラスはなくインターフェースが定義されているのでそれにしたがって実装します。 プラグインの使い方 公式ドキュメントに簡単な使い方が乗っているのでこちらを参考にすれば簡単に導入することができます。以下がサンプルコードで、簡単な流れとしてはinstall()で任意のプラグインをインストールするリクエスト時にプラグイン実行となります。サンプルコードでは、プラグインでkwargsにdbをセットされている為ルートのアクションでdb変数が利用できるようになってます。 from bottle import route, install, template from bottle_sqlite import SQLitePlugin install(SQLitePlugin(dbfile=’/tmp/test.db’)) @route(‘/show/<post_id:int>’) def show(db, post_id): c = db.execute(‘SELECT title, content FROM posts WHERE id = ?’, (post_id,)) row = c.fetchone() return template(‘show_post’, title=row[‘title’], text=row[‘content’]) @route(‘/contact’) def contact_page(): ”’ This callback does not need a db connection. Because the ‘db’ keyword argument is missing, the sqlite plugin ignores this callback completely. ”’ return template(‘contact’) プラグインの作り方 プラグインの作り方も公式ドキュメントにもっともシンプルな形のサンプルがあります。これは実行速度をレスポンスヘッダーにつけて返す処理ですが、サーバ起動時にstopwatchをインストールし、リクエストが来た際にデコレータを実行(表現あってるか分からない)することでリクエストの処理時間は計測できるようになっています。 from bottle import response, install, route import time def stopwatch(callback): def wrapper(*args, **kwargs): start = time.time() body = callback(*args, **kwargs) end = time.time() response.headers[‘X-Exec-Time’] = …

Python Bottleのソースを読む リクエスト・レスポンス編

2016/12/05   -Python
 ,

Pythonの軽量WebフレームワークBottleのソースを読む リクエスト・レスポンス編   Class Hierarchy ここの部分 リクエスト受付からレスポンスまで 前回、サーバの立ち上げ時にルーティングが読み込まれるところまでを確認したので今回はリクエスト受付からレスポンスを返すまでを見てみる。 まずリクエストが来るとwsgiref/handlers.pyのrunが呼ばれ、Bottleの__call__が呼び出される wsgiref/handlers.py self.setup_environ() # リクエストを処理しレスポンスを取得する self.result = application(self.environ, self.start_response) # レスポンスを返す self.finish_response() bottle.py def __call__(self, environ, start_response): “”” Each instance of :class:’Bottle’ is a WSGI application. “”” return self.wsgi(environ, start_response) リクエストを処理する際に、LocalRequestのbindを呼び出しBaseRequestのコンストラクタにてenvironとLocalRequestをセットする。これでBaseRequestのラッパーからパラメータを取得可能になる。レスポンスも同様にLocalResponseのbindを呼び出す。 try: out = None environ[‘bottle.app’] = self request.bind(environ) response.bind() try: self.trigger_hook(‘before_request’) except HTTPResponse: return _e() # ここでリクエストの主処理を実行する out = _inner_handle() return out; finally: if isinstance(out, HTTPResponse): out.apply(response) self.trigger_hook(‘after_request’) BaseRequestのコンストラクタ self.environ = {} if environ is None else environ self.environ[‘bottle.request’] = self リクエスト情報は以下のように取得可能になる def index(): request.forms.get(‘test’) return ‘TOP’ LocalRequestは以下の通りマルチスレッドに対応している #: A thread-safe instance of :class:`LocalRequest`. If accessed from within a #: request …

Python Bottleのソースを読む テンプレート編

2016/12/05   -Python

前回に続きPythonの軽量WebフレームワークBottleのソースを読む テンプレート編 Class Hierarchy ここの部分 Bottleのテンプレートについて Bottleのテンプレートは、Simple、Cheetah、Jinja2、Makoの4種類があり、BaseTemplateを継承しているPythonのテンプレートの種類(参考)http://www.cmscom.jp/blog/af0ga8 テンプレートの使い方 テンプレートの拡張子には以下が利用できる extensions = [‘tpl’, ‘html’, ‘thtml’, ‘stpl’] 例えばjinja2を使う場合は以下のように呼び出すことができる(jinja2をpip installする必要あり) @route(‘/’) def jinja2(): name = ‘text’ return jinja2_template(‘jinja2’, name=name) view {{ name }} テンプレート呼び出しの処理をみてみる 各テンプレートは以下のように設定されている。 functools.partialにfunc templateが渡されている mako_template = functools.partial(template, template_adapter=MakoTemplate) cheetah_template = functools.partial(template, template_adapter=CheetahTemplate) jinja2_template = functools.partial(template, template_adapter=Jinja2Template) jinja2_templateが呼ばれた時の処理 *argsにはjinja2が、**kwargsにはtemplate_adapter=Jinja2Templateが渡される def template(*args, **kwargs): 引数からjinja2テンプレート名を取得 tpl = args[0] if args else None Jinja2Templateを取得 adapter = kwargs.pop(‘template_adapter’, SimpleTemplate) テンプレートパスをlookup(パスは./views/か./) lookup = kwargs.pop(‘template_lookup’, TEMPLATE_PATH) Jinja2Templateをインスタンス化 TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings) BaseTemplateのコンストラクタの最後のprepareでJinja2Templateのprepareが呼ばれる self.prepare(**self.settings) ここではじめてjinja2がimportされる from jinja2 import Environment, FunctionLoader テンプレートのrenderメソッドにてレンダリングしviewを返す return TEMPLATES[tplid].render(kwargs) BottleのテンプレートはBaseTemplateを継承しprepareとrenderを実装することで使える仕組みになっている def prepare(self, **options): “”” Run preparations (parsing, caching, …). It should be possible …

Python Bottleのソースを読む 起動編

2016/12/01   -Python
 ,

Pythonの軽量WebフレームワークBottleのソースを読む 起動編 Bottleとは Bottle is a fast, simple and lightweight WSGI micro web-framework for Python. It is distributed as a single file module and has no dependencies other than the Python Standard Library. Pythonの軽量Webフレームワークで、特徴はシンプルで早く、Pythonの標準ライブラリにも依存していないWebフレームワークであることとフレームワーク本体が1ファイルで構成されていることである Class Hierarchy Doxygenを使って出力した図Bottleは1ファイルながら中でそれぞれのクラス、主にServer、Templateが継承関係にあるのがわかる(コード量は4000行位)。ServerやTemplateクラスはたくさんあるが実際はその中のどれかを選択して利用する形となる 起動 Bottleの起動はrun()を呼び出す方法とコマンドラインインターフェースを使う方法が用意されている run()を使う方法 以下のように記載し起動することでサーバが立ち上がる from bottle import run, route @route(‘/’) def index(): return ‘Hello World’ run(host=’localhost’, port=8000, debug=True) コマンドラインインターフェースを使う場合 以下のコマンドで起動可能 # コントローラを指定 python -m bottle ‘package.controller’ # 説明は省略するが明示的にアプリを指定することも可能 python -m bottle ‘package.controller:app’ controller.py # runは不要 from bottle import ,route @route(‘/’) def index(): return ‘Hello World’ 起動処理を確認する コマンドラインインターフェースを使う場合 mainが2箇所あるが、これはサーバアダプダに必要なライブラリを必要としているからで、1つ目のmainでまずサーバアダプタに必要なライブラリを読み込み2つ目のmainでサーバが起動される仕組みになっている run()でサーバを起動する run()では、渡された引数の値をそれぞれ読み込んだあと最後にServerAdapterのrun()を呼び出している。Bottleでは多くのサーバをServerAdapterを継承することでサポートしており、指定されたサーバを起動するようになっている。指定しない場合はwsgirefがデフォルトで呼ばれる。また、appパラメータは特別指定しなければ、内部で自動的にdefaultが使われるので特別指定する必要はない。 サーバをロードするまで処理を追ってみる まず、Bottleでサポートしているサーバは以下のように宣言してある。 server_names = { ‘cgi’: CGIServer, ‘flup’: FlupFCGIServer, ‘wsgiref’: WSGIRefServer, ‘waitress’: WaitressServer, …

Gitのソースコードをデバッグする

2016/11/30   -Git
 

これまでGitの内側の仕組みなどをチェックしてきて、最近ようやくソースコードをデバッグしてみても処理が追えそうというところまできたので記事にまとめておきます。ただ色々試しながらやった結果なので、もっとよいやり方はあるかもしれません。 emacsとgdbをインストール 今回OSはCentOSを使っていきます。 sudo yum install emacs sudo yum install gdb gitのソースコードをクローンする 今回はGitHubにあるソースコードを利用します。 git clone https://github.com/git/git.git cd git # バージョンを指定してチェックアウトしておきます。 git chekcout -b v2.6.0-rc1 ソースコードをコンパイルする まず必要なライブラリをインストールしてからコンパイルします。 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker make emacsを起動してデバッグをする 環境が整ったので、ここからgdbを起動しgitコマンドのデバッグをしていきます。gdbはそのまま起動しても使えますが、emacsからの方がデバッグしやすいのでemacsからgdbを起動します。 # emacsを起動する emacs -nw # gdbを起動する M-x gdb gdb –annotate=3 git # main関数で止まるようにブレークポイントを指定します (gdb) b main # 実行 (gdb) r デバッガが起動しました。画面上側がコマンドラインで、下側がソースになっています。 # ステップ実行(next) (gdb) n # 変数の内容をチェック (gdb) print argc $1 = 1 # ステップイン(step) (gdb) s # 最後まで実行(continue) (gdb) c gitコマンドを実行した場合、676行目までいき usage と The most commonly used git commands が表示されて終了します。 /* The user didn’t specify a command; give them help */ commit_pager_choice(); …

Gitの参照 – HEADとheadsとtagsとremotes

2016/11/30   -Git
 

Gitの参照についてまとめました。また別記事にてGitの内側について記載しています。 配管(Plumbing)と磁器(Porcelain)Git オブジェクト Gitの内側についておさらい 「git init」すると「.git」ディレクトリができるがその中についてがテーマ普段は使わない配管コマンドと呼ばれる下位レベルのコマンドがある4つのオブジェクトがある blobオブジェクト(ファイルに相当) treeオブジェクト(ディレクトリに相当) commitオブジェクト(commit情報を保持) tagオブジェクト(Tagを保持) Gitの参照って? ここで取り上げるGitの参照は「HEAD」ファイルと「.git/refs」配下のことを示します。「git init」した直後「HEAD」ファイルは「refs/heads/master」を参照し(初期化直後はなにも存在しない)、「.git/refs」配下には、headsとtagsディレクトリがあります。ブランチにcommitするとheads配下にブランチ名のファイルができ、HEADファイルはheads配下のブランチ名を参照します。 # masterにcommit後 # HEADファイル ref: refs/heads/master # refs配下の構造 └── refs ├── heads │   └── master └── tags Gitの参照の種類 Gitの参照の種類は次の通りです。 heads:作業中ブランチのcommitを参照tags:commitをわかりやすくする為の名前付け用remotes:リモートブランチのcommitを参照HEAD:作業中のブランチに対するシンボリック参照。HEADは基本的にheadsを参照しているので、他の参照と区別する為シンボリック参照と呼ばれます 動作確認の為の事前準備 次のような3つのcommitがあるリポジトリを用意しremoteへpushしておきます。 % git log –pretty=oneline master 1f36229bc26825222b191dcd63929392d9d8e2fd third commit 543ee947f5a865e1a998f793120667c3bf89fc80 second commit 23391397b4316d334e9293c4f7d1d601c1f24c4c first commit % git remote add origin git@github.com:taisa007/internal-git.git 次からはこのリポジトリを利用します。クローンする場合はこちらを利用してください。 構成 構成は次の通りです。「.git/refs」ディレクトリ配下にそれぞれheads, remotes, tagsというディレクトリが作られています。 % tree .git └── refs ├── heads │   └── master ├── remotes │   └── origin │   └── master └── tags Gitの参照の解説 「refs」配下にあるファイルはそれぞれ最後のcommitをファイルに記録しています。例えば現在masterは「third commit」にいますが「git log –pretty=oneline master」とすると次のようなcommit履歴が確認できます。 % git log –pretty=oneline master 1f36229bc26825222b191dcd63929392d9d8e2fd third commit 543ee947f5a865e1a998f793120667c3bf89fc80 second commit 23391397b4316d334e9293c4f7d1d601c1f24c4c first commit …