Commits

Atsushi Odagiri  committed 5643426

buildoutize

  • Participants
  • Parent commits 7362295

Comments (0)

Files changed (7)

File bootstrap.py

+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 105417 2009-11-01 15:15:20Z tarek $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+# parsing arguments
+parser = OptionParser()
+parser.add_option("-v", "--version", dest="version",
+                          help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+                   action="store_true", dest="distribute", default=False,
+                   help="Use Disribute rather than Setuptools.")
+
+parser.add_option("-c", None, action="store", dest="config_file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+    args += ['-c', options.config_file]
+
+if options.version is not None:
+    VERSION = '==%s' % options.version
+else:
+    VERSION = ''
+
+USE_DISTRIBUTE = options.distribute
+args = args + ['bootstrap']
+
+try:
+    import pkg_resources
+    import setuptools
+    if not hasattr(pkg_resources, '_distribute'):
+        raise ImportError
+except ImportError:
+    ez = {}
+    if USE_DISTRIBUTE:
+        exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
+                         ).read() in ez
+        ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
+    else:
+        exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                             ).read() in ez
+        ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+    reload(sys.modules['pkg_resources'])
+    import pkg_resources
+
+if sys.platform == 'win32':
+    def quote(c):
+        if ' ' in c:
+            return '"%s"' % c # work around spawn lamosity on windows
+        else:
+            return c
+else:
+    def quote (c):
+        return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws  = pkg_resources.working_set
+
+if USE_DISTRIBUTE:
+    requirement = 'distribute'
+else:
+    requirement = 'setuptools'
+
+if is_jython:
+    import subprocess
+
+    assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+           quote(tmpeggs), 'zc.buildout' + VERSION],
+           env=dict(os.environ,
+               PYTHONPATH=
+               ws.find(pkg_resources.Requirement.parse(requirement)).location
+               ),
+           ).wait() == 0
+
+else:
+    assert os.spawnle(
+        os.P_WAIT, sys.executable, quote (sys.executable),
+        '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
+        dict(os.environ,
+            PYTHONPATH=
+            ws.find(pkg_resources.Requirement.parse(requirement)).location
+            ),
+        ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout' + VERSION)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)

File buildout.cfg

+[buildout]
+parts = 
+    sphinx
+
+[sphinx]
+recipe = collective.recipe.sphinxbuilder
+source = ${buildout:directory}/docs-source
+build = ${buildout:directory}/docs

File do-it-yourself-framework_ja.txt

-A Do-It-Yourself Framework
-++++++++++++++++++++++++++
-
-:author: Ian Bicking <ianb@colorstudy.com>
-:translator: Atsushi Odagiri <aodagx@gmail.com>
-:revision: $Rev: 7181 $
-:date: $LastChangedDate: 2008-01-08 09:46:01 +0900 (火, 08  1 2008) $
-:original: http://pythonpaste.org/do-it-yourself-framework.html
-
-.. contents::
-
-.. comments:
-
-   Explain SCRIPT_NAME/PATH_INFO better
-
-Introduction and Audience
-=========================
-
-この短いチュートリアルは、Pasteが可能にし、推奨するアーキテクチャの例です。
-また、WSGIについても軽く触れます。
-
-これは、Pasteのすべてに関する紹介ではありません。
-説明しているのはほんの一部です。
-また、すべての人に、フレームワークを乗り換え、自らのフレームワークを作成することを推奨するものでもありません。(正直なところそうなっても気にしません)。
-目的は、この文書を読み終えた方が、このアーキテクチャを用いたフレームワークをより快適に使えるようになることと、覆い隠された内部をより理解することにあります。
-
-What is WSGI?
-=============
-
-最も単純言えば、WSGIとは、WebサーバーとWebアプリケーション間のインターフェイスです。
-以下で説明するのは、WSGIの構造についです。
-上位のレベルから見れば、WSGIはwebリクエストを非常に公平で公式な方法で、コードに引き渡します。
-しかし、それだけではありません!
-WSGIは、単なるHTTP以上のものなのです。
-これらの内容は、HTTPとほんの *ささいな* 違いにしか見えないでしょう。
-しかし、この小さな違いが重要なのです。:
-
-
-* CGIのように環境をコードに引き渡します。 ``REMOTE_USER`` などのデータもsecureに引き渡されます。
-
-* CGIのような環境が、もっと多くのコンテキストと渡されます。特に、1つのパスではなく2つのパスが渡されます。 ``SCRIPT_NAME`` と ``PATH_INFO`` です。
-  ``SCRIPT_NAME`` はどのようにしてここまできたか、 ``PATH_INFO`` は、なにが残っているかを表しています。
-
-* 独自の拡張をWSGI環境に置くことができます。また通常はそうすべきです。
-  コールバックや追加情報など、あなたが望むあらゆるPythonオブジェクトを置くことが許されています。
-  これらは、HTTPヘッダーに置くことができないものです。
-
-これらの特徴により、WSGIはWebサーバーとアプリケーションの間を取り持つだけでなく、すべてのレベルでのやりとりが可能になります。
-つまり、Webアプリケーションを再利用可能なカプセル化したライブラリのように扱えるようになり、機能を再利用可能にします。
-
-Writing a WSGI Application
-==========================
-
-最初に説明するのは、
-`WSGI
-<http://www.python.org/peps/pep-0333.html>`_ の初歩的な使い方です。
-ここで簡単に説明しますが、WSGIの規格を参照してください。
-
-
-* *WSGI アプリケーション* を書こうとしています。これは、要求に応じるオブジェクトです。
-  アプリケーションは単に ``environ`` と ``start_response`` の2つの引数を受け取る呼び出し可能(関数のようなもの)なオブジェクトです。
-
-* 環境は、 ``REQUEST_METHOD``, ``HTTP_HOST`` など、CGI環境変数を持っています。
-
-* また、 ``wsgi.input`` (POSTリクエストの入力内容) のような特殊なキーも持っています。
-
-* ``start_response`` は、レスポンスを返し始めるための関数です。
-  ここで、ステータスやヘッダを与えます。
-
-* 最終的に、アプリケーションは、レスポンスボディをイテレータで返します。
-  (通常は、複数の文字列のリストか、すべてをまとめた1つだけの文字列を含むリストになります。)
-
-
-そして、一番簡単なアプリケーションは以下のようになります::
-
-    def app(environ, start_response):
-        start_response('200 OK', [('content-type', 'text/html')])
-        return ['Hello world!']
-
-しかし、これではまだ不十分です。
-想像がつくと思いますが、これではブラウザでアクセスできません。
-
-良い方法はたくさんありましが、このチュートリアルでは良い方法ではなく分かりやすい方法を使います。
-
-なので、以下の文をファイルの末尾に付け加えるだけにしましょう。::
-
-    if __name__ == '__main__':
-        from paste import httpserver
-        httpserver.serve(app, host='127.0.0.1', port='8080')
-
-そして、http://localhost:8080 を確認してみましょう。
-このアプリケーションが動いています。
-WSGIサーバーの動作を理解したければ、WSGI規格の `CGI WSGI server
-<http://www.python.org/peps/pep-0333.html#the-server-gateway-side>`_  を確認することをお勧めします。
-
-An Interactive App
-------------------
-
-さきほどのアプリケーションはとりたてて興味深いものではありませんでした。
-最低限の対話性を付け加えてみましょう。
-そうするには、フォームを表示し、そのフォームフィールドをパースするようにします。::
-
-    from paste.request import parse_formvars
-
-    def app(environ, start_response):
-        fields = parse_formvars(environ)
-        if environ['REQUEST_METHOD'] == 'POST':
-            start_response('200 OK', [('content-type', 'text/html')])
-            return ['Hello, ', fields['name'], '!']
-        else:
-            start_response('200 OK', [('content-type', 'text/html')])
-            return ['<form method="POST">Name: <input type="text" '
-                    'name="name"><input type="submit"></form>']
-
-``parse_formvars`` 関数は、WSGI環境を受け取り、
-`cgi <http://python.org/doc/current/lib/module-cgi.html>`_ モジュール(``FieldStorage`` クラス)
-を呼び出して、MultiDictにつめて返します。
-
-Now For a Framework
-===================
-
-これまでの内容は少々粗雑に感じるでしょう。
-このままでは、REQUEST_METHODのようなものをもっと判定しなくてはならなくなりますし、
-複数ページを取り扱う方法が分かりません。
-
-一般的なアプリケーションのためのフレームワークが欲しくなります。
-このチュートリアルでは、*オブジェクトパブリッシャー* を実装します。
-これは、ZopeやQuixote、Cherrypy で見たことがあるかもしれません。
-
-Object Publishing
------------------
-
-典型的なPythonオブジェクトパブリッシャーは、 ``/`` を ``.`` に変換します。
-つまり、 ``/articles/view?id=5`` は、 ``root.articles.view(id=5)`` と変換されます。
-
-もちろん、なんらかのルートオブジェクトが必要なので、それを渡すようにします。
-
-    class ObjectPublisher(object):
-
-        def __init__(self, root):
-            self.root = root
-
-        def __call__(self, environ, start_response):
-            ...
-
-    app = ObjectPublisher(my_root_object)
-
-``__call__`` をオーバーライドするのは、
-``ObjectPublisher`` のインスタンスを関数のように呼び出し可能なWSGIアプリケーションにするためです。
-このあとやらなくてはならないのは、 ``environ`` を表示しようとしているものに変換してWSGIのレスポンスとして返すことです。
-
-The Path
---------
-
-WSGIは要求されたパスを ``SCRIPT_NAME`` と ``PATH_INFO`` の2つの変数にします。
-``SCRIPT_NAME`` は *たどり着く* のに使われたものです。
-``PATH_INFO`` は、まだ残されているものです。
-フレームワークがオブジェクトを発見するために使うのは、この部分です。
-この2つを一緒にすると、今リクエストされているフルパスになります。
-これは、正しいURLを作成するのに役立ちます。
-この状態を必ず守るようにします。
-
-そして、これが ``__call__`` の実装です。::
-
-    def __call__(self, environ, start_response):
-        fields = parse_formvars(environ)
-        obj = self.find_object(self.root, environ)
-        response_body = obj(**fields.mixed())
-        start_response('200 OK', [('content-type', 'text/html')])
-        return [response_body]
-
-    def find_object(self, obj, environ):
-        path_info = environ.get('PATH_INFO', '')
-        if not path_info or path_info == '/':
-            # We've arrived!
-            return obj
-        # PATH_INFO always starts with a /, so we'll get rid of it:
-        path_info = path_info.lstrip('/')
-        # Then split the path into the "next" chunk, and everything
-        # after it ("rest"):
-        parts = path_info.split('/', 1)
-        next = parts[0]
-        if len(parts) == 1:
-            rest = ''
-        else:
-            rest = '/' + parts[1]
-        # Hide private methods/attributes:
-        assert not next.startswith('_')
-        # Now we get the attribute; getattr(a, 'b') is equivalent
-        # to a.b...
-        next_obj = getattr(obj, next)
-        # Now fix up SCRIPT_NAME and PATH_INFO...
-        environ['SCRIPT_NAME'] += '/' + next
-        environ['PATH_INFO'] = rest
-        # and now parse the remaining part of the URL...
-        return self.find_object(next_obj, environ)
-
-これで、フレームワークを獲得しました。
-
-Taking It For a Ride
---------------------
-
-では、小さなアプリケーションを書いてみましょう。
-さきほどの ``ObjectPublisher`` クラスは、 ``objectpub`` モジュールにあります。::
-
-    from objectpub import ObjectPublisher
-
-    class Root(object):
-
-        # The "index" method:
-        def __call__(self):
-            return '''
-            <form action="welcome">
-            Name: <input type="text" name="name">
-            <input type="submit">
-            </form>
-            '''
-
-        def welcome(self, name):
-            return 'Hello %s!' % name
-
-    app = ObjectPublisher(Root())
-
-    if __name__ == '__main__':
-        from paste import httpserver
-        httpserver.serve(app, host='127.0.0.1', port='8080')
-
-これだけです!
-ただ、ちょっと待ってください。
-まだ大きな問題が残っています。
-例えば、ヘッダーを設定するにはどうすればいいのでしょう?
-``404 Not Found`` を返す代わりに、アトリビュートエラーとしたい場合もあるでしょう。
-ここから少しずつ修正していきましょう。
-
-Give Me More!
--------------
-
-なにかが足りないと感じていることでしょう。
-
-特に、ヘッダを設定する方法がありませんし、リクエストの情報が少ししかありません。
-
-::
-
-    # これは、単なるdictのようなオブジェクトで、ケースセンシティブなキーを持ちます。
-    from paste.response import HeaderDict
-
-    class Request(object):
-        def __init__(self, environ):
-            self.environ = environ
-            self.fields = parse_formvars(environ)
-
-    class Response(object):
-        def __init__(self):
-            self.headers = HeaderDict(
-                {'content-type': 'text/html'})
-
-
-では、ちょっとしたトリックを説明しましょう。(原文ではeachとなっているが、teachの間違い?)
-メソッドのシグネチャを変えたくはありません。
-しかし、リクエストとレスポンスのオブジェクトを普通のグローバル変数に置くわけにはいきません。
-なぜなら、スレッドセーフにしたいからです。
-全てのスレッドが同じグローバル変数を見てしまうからです。(たとえそれが、違うリクエストの処理だったとしても)
-
-しかし、Python2.4で、"スレッドローカル値"の概念が導入されました。
-あるスレッドからしかアクセスできない値です。
-これは、 `threading.local <http://docs.python.org/lib/module-threading.html>`_ にあります。
-``local`` インスタンスを作成したら、それに設定したすべてのアトリビュートは、
-設定したスレッドからしかアクセスできないようになります。
-では、リクエストとレスポンスのオブジェクトを設定するようにしましょう。
-
-まず、 ``__call__`` 関数が以下のようになっていることを思い出しましょう。::
-
-    class ObjectPublisher(object):
-        ...
-
-        def __call__(self, environ, start_response):
-            fields = parse_formvars(environ)
-            obj = self.find_object(self.root, environ)
-            response_body = obj(**fields.mixed())
-            start_response('200 OK', [('content-type', 'text/html')])
-            return [response_body]
-
-このように変更します。::
-
-    import threading
-    webinfo = threading.local()
-
-        def __call__(self, environ, start_response):
-            webinfo.request = Request(environ)
-            webinfo.response = Response()
-            obj = self.find_object(self.root, environ)
-            response_body = obj(**dict(webinfo.request.fields))
-            start_response('200 OK', webinfo.response.headers.items())
-            return [response_body]
-
-
-メソッドでは、このように使えます。::
-
-    class Root:
-        def rss(self):
-            webinfo.response.headers['content-type'] = 'text/xml'
-            ...
-
-その気になれば、 `cookies
-<http://python.org/doc/current/lib/module-Cookie.html>`_ のハンドルもこれらのオブジェクトでできます。
-しかし、今回はそこまでやらないことにします。
-フレームワークができました。
-
-WSGI Middleware
-===============
-
-`Middleware
-<http://www.python.org/peps/pep-0333.html#middleware-components-that-play-both-sides>`_ WSGIやPasteの中で、Middlwareはややとっつきにくく感じるでしょう。
-
-ミドルウェアは何ものでしょう?
-ミドルウェアは、仲介者として働くソフトウェアです。
-
-
-早速1つ書いてみましょう。
-あなたの挨拶を誰からでも見られてしまわないように、認証ミドルウェアを書いてみます。
-
-
-HTTP認証を使いましょう。人々を少しだけけむに巻くことができます。
-HTTP認証は非常に簡単です。:
-
-* 認証が必要になったら、 ``401 Authentication
-  Required``  ステータスを、 ``WWW-Authenticate: Basic realm="This
-  Realm"`` ヘッダーとともに、返します。
-
-* クライアントは、 ``Authorization: Basic
-  encoded_info`` ヘッダーを送り返します。
-
-* この "encoded_info" は、 ``username:password`` をbase-64エンコーディングしたものです。
-
-どうすれば実現できるでしょう?
-そう、"middleware"を書きます。
-つまり、リクエストを違うアプリケーションに渡してしまいます。
-リクエスト変更したり、レスポンスを変更したりできます。
-ただし、この場合は、ときにリクエストを渡さないようにするだけです。
-(401レスポンスを返したい場合など)
-
-
-とても簡単なミドルウェアの例です。
-レスポンスを大文字にしています。::
-
-    class Capitalizer(object):
-
-        # We generally pass in the application to be wrapped to
-        # the middleware constructor:
-        def __init__(self, wrap_app):
-            self.wrap_app = wrap_app
-
-        def __call__(self, environ, start_response):
-            # We call the application we are wrapping with the
-            # same arguments we get...
-            response_iter = self.wrap_app(environ, start_response)
-            # then change the response...
-            response_string = ''.join(response_iter)
-            return [response_string.upper()]
-
-技術的には、完全に正しい方法というわけではありません。
-なぜなら、レスポンスボディを返す方法は2通りあるからです。
-しかし、詳細には立ち入らないことにします。
-
-`paste.wsgilib.intercept_output
-<http://pythonpaste.org/module-paste.wsgilib.html#intercept_output>`_ は、
-この部分をきちんと実装したものです。
-
-それでは、いくらか使い物になるコードです。認証::
-
-
-    class AuthMiddleware(object):
-
-        def __init__(self, wrap_app):
-            self.wrap_app = wrap_app
-
-        def __call__(self, environ, start_response):
-            if not self.authorized(environ.get('HTTP_AUTHORIZATION')):
-                # Essentially self.auth_required is a WSGI application
-                # that only knows how to respond with 401...
-                return self.auth_required(environ, start_response)
-            # But if everything is okay, then pass everything through
-            # to the application we are wrapping...
-            return self.wrap_app(environ, start_response)
-
-        def authorized(self, auth_header):
-            if not auth_header:
-                # If they didn't give a header, they better login...
-                return False
-            # .split(None, 1) means split in two parts on whitespace:
-            auth_type, encoded_info = auth_header.split(None, 1)
-            assert auth_type.lower() == 'basic'
-            unencoded_info = encoded_info.decode('base64')
-            username, password = unencoded_info.split(':', 1)
-            return self.check_password(username, password)
-
-        def check_password(self, username, password):
-            # Not very high security authentication...
-            return username == password
-
-        def auth_required(self, environ, start_response):
-            start_response('401 Authentication Required',
-                [('Content-type', 'text/html'),
-                 ('WWW-Authenticate', 'Basic realm="this realm"')])
-            return ["""
-            <html>
-             <head><title>Authentication Required</title></head>
-             <body>
-              <h1>Authentication Required</h1>
-              If you can't get in, then stay out.
-             </body>
-            </html>"""]
-
-
-
-どうやって使えばいいでしょう?
-::
-
-    app = ObjectPublisher(Root())
-    wrapped_app = AuthMiddleware(app)
-
-    if __name__ == '__main__':
-        from paste import httpserver
-        httpserver.serve(wrapped_app, host='127.0.0.1', port='8080')
-
-
-これでミドルウェアもできました! ヒャッホー!
-
-Give Me More Middleware!
-------------------------
-
-自分で作ったもの以外にも、他の人々が作ったミドルウェアを使うのも簡単です。
-自分で作る必要はありません。
-ここまで読んできたのであれば、恐らく何回か例外に出会っているでしょう。
-そして、コンソールに表示されている例外レポートを目の当たりにしているに違いありません。
-少し簡単にしましょう、ブラウザ上で例外を確認できるようにします。
-
-::
-
-    app = ObjectPublisher(Root())
-    wrapped_app = AuthMiddleware(app)
-    from paste.exceptions.errormiddleware import ErrorMiddleware
-    exc_wrapped_app = ErrorMiddleware(wrapped_app)
-
-簡単ですね!しかし、 *もっと* いいものが欲しいなら...
-
-::
-
-    app = ObjectPublisher(Root())
-    wrapped_app = AuthMiddleware(app)
-    from paste.evalexception import EvalException
-    exc_wrapped_app = EvalException(wrapped_app)
-
-エラーを発生させてみましょう。
-ちいさな + をクリックしてください。
-ボックスの中に何か入力してみましょう。
-
-Configuration
-=============
-
-フレームワークとアプリケーションを作成しました。
-(私が示してきたものよりもはるかにいいものになっていると確信しています。)
-これらを手でつなぎ合わせるのは、幾分粗雑と感じるかもしれません。
-
-そうでなくても、誰かが他の場所にインストールしたり、違う構成にしたりするときに、困ることでしょう。
-
-だから、アプリケーションの構成から、設定を分離しておきたいのです。
-
-What's Next?
-============
-
-まだ続きがあります, 今後構成についても話す予定です。(`Paste Deploy
-<http://pythonpaste.org/deploy/>`_ を使います)。
-そして、パッケージングやプラグインについても短い紹介ができたらいいと思います。
-そのときは、 `私のブログ <http://blog.ianbicking.org>`_ で、告知します。

File docs-source/conf.py

+# -*- coding: utf-8 -*-
+#
+# Translations documentation build configuration file, created by
+# sphinx-quickstart on Tue Sep 14 12:45:40 2010.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Translations'
+copyright = u'2010, Atsushi Odagiri'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Translationsdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'Translations.tex', u'Translations Documentation',
+   u'Atsushi Odagiri', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True

File docs-source/do-it-yourself-framework_ja.rst

+A Do-It-Yourself Framework
+++++++++++++++++++++++++++
+
+:author: Ian Bicking <ianb@colorstudy.com>
+:translator: Atsushi Odagiri <aodagx@gmail.com>
+:revision: $Rev: 7181 $
+:date: $LastChangedDate: 2008-01-08 09:46:01 +0900 (火, 08  1 2008) $
+:original: http://pythonpaste.org/do-it-yourself-framework.html
+
+.. contents::
+
+.. comments:
+
+   Explain SCRIPT_NAME/PATH_INFO better
+
+Introduction and Audience
+=========================
+
+この短いチュートリアルは、Pasteが可能にし、推奨するアーキテクチャの例です。
+また、WSGIについても軽く触れます。
+
+これは、Pasteのすべてに関する紹介ではありません。
+説明しているのはほんの一部です。
+また、すべての人に、フレームワークを乗り換え、自らのフレームワークを作成することを推奨するものでもありません。(正直なところそうなっても気にしません)。
+目的は、この文書を読み終えた方が、このアーキテクチャを用いたフレームワークをより快適に使えるようになることと、覆い隠された内部をより理解することにあります。
+
+What is WSGI?
+=============
+
+最も単純言えば、WSGIとは、WebサーバーとWebアプリケーション間のインターフェイスです。
+以下で説明するのは、WSGIの構造についです。
+上位のレベルから見れば、WSGIはwebリクエストを非常に公平で公式な方法で、コードに引き渡します。
+しかし、それだけではありません!
+WSGIは、単なるHTTP以上のものなのです。
+これらの内容は、HTTPとほんの *ささいな* 違いにしか見えないでしょう。
+しかし、この小さな違いが重要なのです。:
+
+
+* CGIのように環境をコードに引き渡します。 ``REMOTE_USER`` などのデータもsecureに引き渡されます。
+
+* CGIのような環境が、もっと多くのコンテキストと渡されます。特に、1つのパスではなく2つのパスが渡されます。 ``SCRIPT_NAME`` と ``PATH_INFO`` です。
+  ``SCRIPT_NAME`` はどのようにしてここまできたか、 ``PATH_INFO`` は、なにが残っているかを表しています。
+
+* 独自の拡張をWSGI環境に置くことができます。また通常はそうすべきです。
+  コールバックや追加情報など、あなたが望むあらゆるPythonオブジェクトを置くことが許されています。
+  これらは、HTTPヘッダーに置くことができないものです。
+
+これらの特徴により、WSGIはWebサーバーとアプリケーションの間を取り持つだけでなく、すべてのレベルでのやりとりが可能になります。
+つまり、Webアプリケーションを再利用可能なカプセル化したライブラリのように扱えるようになり、機能を再利用可能にします。
+
+Writing a WSGI Application
+==========================
+
+最初に説明するのは、
+`WSGI
+<http://www.python.org/peps/pep-0333.html>`_ の初歩的な使い方です。
+ここで簡単に説明しますが、WSGIの規格を参照してください。
+
+
+* *WSGI アプリケーション* を書こうとしています。これは、要求に応じるオブジェクトです。
+  アプリケーションは単に ``environ`` と ``start_response`` の2つの引数を受け取る呼び出し可能(関数のようなもの)なオブジェクトです。
+
+* 環境は、 ``REQUEST_METHOD``, ``HTTP_HOST`` など、CGI環境変数を持っています。
+
+* また、 ``wsgi.input`` (POSTリクエストの入力内容) のような特殊なキーも持っています。
+
+* ``start_response`` は、レスポンスを返し始めるための関数です。
+  ここで、ステータスやヘッダを与えます。
+
+* 最終的に、アプリケーションは、レスポンスボディをイテレータで返します。
+  (通常は、複数の文字列のリストか、すべてをまとめた1つだけの文字列を含むリストになります。)
+
+
+そして、一番簡単なアプリケーションは以下のようになります::
+
+    def app(environ, start_response):
+        start_response('200 OK', [('content-type', 'text/html')])
+        return ['Hello world!']
+
+しかし、これではまだ不十分です。
+想像がつくと思いますが、これではブラウザでアクセスできません。
+
+良い方法はたくさんありましが、このチュートリアルでは良い方法ではなく分かりやすい方法を使います。
+
+なので、以下の文をファイルの末尾に付け加えるだけにしましょう。::
+
+    if __name__ == '__main__':
+        from paste import httpserver
+        httpserver.serve(app, host='127.0.0.1', port='8080')
+
+そして、http://localhost:8080 を確認してみましょう。
+このアプリケーションが動いています。
+WSGIサーバーの動作を理解したければ、WSGI規格の `CGI WSGI server
+<http://www.python.org/peps/pep-0333.html#the-server-gateway-side>`_  を確認することをお勧めします。
+
+An Interactive App
+------------------
+
+さきほどのアプリケーションはとりたてて興味深いものではありませんでした。
+最低限の対話性を付け加えてみましょう。
+そうするには、フォームを表示し、そのフォームフィールドをパースするようにします。::
+
+    from paste.request import parse_formvars
+
+    def app(environ, start_response):
+        fields = parse_formvars(environ)
+        if environ['REQUEST_METHOD'] == 'POST':
+            start_response('200 OK', [('content-type', 'text/html')])
+            return ['Hello, ', fields['name'], '!']
+        else:
+            start_response('200 OK', [('content-type', 'text/html')])
+            return ['<form method="POST">Name: <input type="text" '
+                    'name="name"><input type="submit"></form>']
+
+``parse_formvars`` 関数は、WSGI環境を受け取り、
+`cgi <http://python.org/doc/current/lib/module-cgi.html>`_ モジュール(``FieldStorage`` クラス)
+を呼び出して、MultiDictにつめて返します。
+
+Now For a Framework
+===================
+
+これまでの内容は少々粗雑に感じるでしょう。
+このままでは、REQUEST_METHODのようなものをもっと判定しなくてはならなくなりますし、
+複数ページを取り扱う方法が分かりません。
+
+一般的なアプリケーションのためのフレームワークが欲しくなります。
+このチュートリアルでは、*オブジェクトパブリッシャー* を実装します。
+これは、ZopeやQuixote、Cherrypy で見たことがあるかもしれません。
+
+Object Publishing
+-----------------
+
+典型的なPythonオブジェクトパブリッシャーは、 ``/`` を ``.`` に変換します。
+つまり、 ``/articles/view?id=5`` は、 ``root.articles.view(id=5)`` と変換されます。
+
+もちろん、なんらかのルートオブジェクトが必要なので、それを渡すようにします。
+
+    class ObjectPublisher(object):
+
+        def __init__(self, root):
+            self.root = root
+
+        def __call__(self, environ, start_response):
+            ...
+
+    app = ObjectPublisher(my_root_object)
+
+``__call__`` をオーバーライドするのは、
+``ObjectPublisher`` のインスタンスを関数のように呼び出し可能なWSGIアプリケーションにするためです。
+このあとやらなくてはならないのは、 ``environ`` を表示しようとしているものに変換してWSGIのレスポンスとして返すことです。
+
+The Path
+--------
+
+WSGIは要求されたパスを ``SCRIPT_NAME`` と ``PATH_INFO`` の2つの変数にします。
+``SCRIPT_NAME`` は *たどり着く* のに使われたものです。
+``PATH_INFO`` は、まだ残されているものです。
+フレームワークがオブジェクトを発見するために使うのは、この部分です。
+この2つを一緒にすると、今リクエストされているフルパスになります。
+これは、正しいURLを作成するのに役立ちます。
+この状態を必ず守るようにします。
+
+そして、これが ``__call__`` の実装です。::
+
+    def __call__(self, environ, start_response):
+        fields = parse_formvars(environ)
+        obj = self.find_object(self.root, environ)
+        response_body = obj(**fields.mixed())
+        start_response('200 OK', [('content-type', 'text/html')])
+        return [response_body]
+
+    def find_object(self, obj, environ):
+        path_info = environ.get('PATH_INFO', '')
+        if not path_info or path_info == '/':
+            # We've arrived!
+            return obj
+        # PATH_INFO always starts with a /, so we'll get rid of it:
+        path_info = path_info.lstrip('/')
+        # Then split the path into the "next" chunk, and everything
+        # after it ("rest"):
+        parts = path_info.split('/', 1)
+        next = parts[0]
+        if len(parts) == 1:
+            rest = ''
+        else:
+            rest = '/' + parts[1]
+        # Hide private methods/attributes:
+        assert not next.startswith('_')
+        # Now we get the attribute; getattr(a, 'b') is equivalent
+        # to a.b...
+        next_obj = getattr(obj, next)
+        # Now fix up SCRIPT_NAME and PATH_INFO...
+        environ['SCRIPT_NAME'] += '/' + next
+        environ['PATH_INFO'] = rest
+        # and now parse the remaining part of the URL...
+        return self.find_object(next_obj, environ)
+
+これで、フレームワークを獲得しました。
+
+Taking It For a Ride
+--------------------
+
+では、小さなアプリケーションを書いてみましょう。
+さきほどの ``ObjectPublisher`` クラスは、 ``objectpub`` モジュールにあります。::
+
+    from objectpub import ObjectPublisher
+
+    class Root(object):
+
+        # The "index" method:
+        def __call__(self):
+            return '''
+            <form action="welcome">
+            Name: <input type="text" name="name">
+            <input type="submit">
+            </form>
+            '''
+
+        def welcome(self, name):
+            return 'Hello %s!' % name
+
+    app = ObjectPublisher(Root())
+
+    if __name__ == '__main__':
+        from paste import httpserver
+        httpserver.serve(app, host='127.0.0.1', port='8080')
+
+これだけです!
+ただ、ちょっと待ってください。
+まだ大きな問題が残っています。
+例えば、ヘッダーを設定するにはどうすればいいのでしょう?
+``404 Not Found`` を返す代わりに、アトリビュートエラーとしたい場合もあるでしょう。
+ここから少しずつ修正していきましょう。
+
+Give Me More!
+-------------
+
+なにかが足りないと感じていることでしょう。
+
+特に、ヘッダを設定する方法がありませんし、リクエストの情報が少ししかありません。
+
+::
+
+    # これは、単なるdictのようなオブジェクトで、ケースセンシティブなキーを持ちます。
+    from paste.response import HeaderDict
+
+    class Request(object):
+        def __init__(self, environ):
+            self.environ = environ
+            self.fields = parse_formvars(environ)
+
+    class Response(object):
+        def __init__(self):
+            self.headers = HeaderDict(
+                {'content-type': 'text/html'})
+
+
+では、ちょっとしたトリックを説明しましょう。(原文ではeachとなっているが、teachの間違い?)
+メソッドのシグネチャを変えたくはありません。
+しかし、リクエストとレスポンスのオブジェクトを普通のグローバル変数に置くわけにはいきません。
+なぜなら、スレッドセーフにしたいからです。
+全てのスレッドが同じグローバル変数を見てしまうからです。(たとえそれが、違うリクエストの処理だったとしても)
+
+しかし、Python2.4で、"スレッドローカル値"の概念が導入されました。
+あるスレッドからしかアクセスできない値です。
+これは、 `threading.local <http://docs.python.org/lib/module-threading.html>`_ にあります。
+``local`` インスタンスを作成したら、それに設定したすべてのアトリビュートは、
+設定したスレッドからしかアクセスできないようになります。
+では、リクエストとレスポンスのオブジェクトを設定するようにしましょう。
+
+まず、 ``__call__`` 関数が以下のようになっていることを思い出しましょう。::
+
+    class ObjectPublisher(object):
+        ...
+
+        def __call__(self, environ, start_response):
+            fields = parse_formvars(environ)
+            obj = self.find_object(self.root, environ)
+            response_body = obj(**fields.mixed())
+            start_response('200 OK', [('content-type', 'text/html')])
+            return [response_body]
+
+このように変更します。::
+
+    import threading
+    webinfo = threading.local()
+
+        def __call__(self, environ, start_response):
+            webinfo.request = Request(environ)
+            webinfo.response = Response()
+            obj = self.find_object(self.root, environ)
+            response_body = obj(**dict(webinfo.request.fields))
+            start_response('200 OK', webinfo.response.headers.items())
+            return [response_body]
+
+
+メソッドでは、このように使えます。::
+
+    class Root:
+        def rss(self):
+            webinfo.response.headers['content-type'] = 'text/xml'
+            ...
+
+その気になれば、 `cookies
+<http://python.org/doc/current/lib/module-Cookie.html>`_ のハンドルもこれらのオブジェクトでできます。
+しかし、今回はそこまでやらないことにします。
+フレームワークができました。
+
+WSGI Middleware
+===============
+
+`Middleware
+<http://www.python.org/peps/pep-0333.html#middleware-components-that-play-both-sides>`_ WSGIやPasteの中で、Middlwareはややとっつきにくく感じるでしょう。
+
+ミドルウェアは何ものでしょう?
+ミドルウェアは、仲介者として働くソフトウェアです。
+
+
+早速1つ書いてみましょう。
+あなたの挨拶を誰からでも見られてしまわないように、認証ミドルウェアを書いてみます。
+
+
+HTTP認証を使いましょう。人々を少しだけけむに巻くことができます。
+HTTP認証は非常に簡単です。:
+
+* 認証が必要になったら、 ``401 Authentication
+  Required``  ステータスを、 ``WWW-Authenticate: Basic realm="This
+  Realm"`` ヘッダーとともに、返します。
+
+* クライアントは、 ``Authorization: Basic
+  encoded_info`` ヘッダーを送り返します。
+
+* この "encoded_info" は、 ``username:password`` をbase-64エンコーディングしたものです。
+
+どうすれば実現できるでしょう?
+そう、"middleware"を書きます。
+つまり、リクエストを違うアプリケーションに渡してしまいます。
+リクエスト変更したり、レスポンスを変更したりできます。
+ただし、この場合は、ときにリクエストを渡さないようにするだけです。
+(401レスポンスを返したい場合など)
+
+
+とても簡単なミドルウェアの例です。
+レスポンスを大文字にしています。::
+
+    class Capitalizer(object):
+
+        # We generally pass in the application to be wrapped to
+        # the middleware constructor:
+        def __init__(self, wrap_app):
+            self.wrap_app = wrap_app
+
+        def __call__(self, environ, start_response):
+            # We call the application we are wrapping with the
+            # same arguments we get...
+            response_iter = self.wrap_app(environ, start_response)
+            # then change the response...
+            response_string = ''.join(response_iter)
+            return [response_string.upper()]
+
+技術的には、完全に正しい方法というわけではありません。
+なぜなら、レスポンスボディを返す方法は2通りあるからです。
+しかし、詳細には立ち入らないことにします。
+
+`paste.wsgilib.intercept_output
+<http://pythonpaste.org/module-paste.wsgilib.html#intercept_output>`_ は、
+この部分をきちんと実装したものです。
+
+それでは、いくらか使い物になるコードです。認証::
+
+
+    class AuthMiddleware(object):
+
+        def __init__(self, wrap_app):
+            self.wrap_app = wrap_app
+
+        def __call__(self, environ, start_response):
+            if not self.authorized(environ.get('HTTP_AUTHORIZATION')):
+                # Essentially self.auth_required is a WSGI application
+                # that only knows how to respond with 401...
+                return self.auth_required(environ, start_response)
+            # But if everything is okay, then pass everything through
+            # to the application we are wrapping...
+            return self.wrap_app(environ, start_response)
+
+        def authorized(self, auth_header):
+            if not auth_header:
+                # If they didn't give a header, they better login...
+                return False
+            # .split(None, 1) means split in two parts on whitespace:
+            auth_type, encoded_info = auth_header.split(None, 1)
+            assert auth_type.lower() == 'basic'
+            unencoded_info = encoded_info.decode('base64')
+            username, password = unencoded_info.split(':', 1)
+            return self.check_password(username, password)
+
+        def check_password(self, username, password):
+            # Not very high security authentication...
+            return username == password
+
+        def auth_required(self, environ, start_response):
+            start_response('401 Authentication Required',
+                [('Content-type', 'text/html'),
+                 ('WWW-Authenticate', 'Basic realm="this realm"')])
+            return ["""
+            <html>
+             <head><title>Authentication Required</title></head>
+             <body>
+              <h1>Authentication Required</h1>
+              If you can't get in, then stay out.
+             </body>
+            </html>"""]
+
+
+
+どうやって使えばいいでしょう?
+::
+
+    app = ObjectPublisher(Root())
+    wrapped_app = AuthMiddleware(app)
+
+    if __name__ == '__main__':
+        from paste import httpserver
+        httpserver.serve(wrapped_app, host='127.0.0.1', port='8080')
+
+
+これでミドルウェアもできました! ヒャッホー!
+
+Give Me More Middleware!
+------------------------
+
+自分で作ったもの以外にも、他の人々が作ったミドルウェアを使うのも簡単です。
+自分で作る必要はありません。
+ここまで読んできたのであれば、恐らく何回か例外に出会っているでしょう。
+そして、コンソールに表示されている例外レポートを目の当たりにしているに違いありません。
+少し簡単にしましょう、ブラウザ上で例外を確認できるようにします。
+
+::
+
+    app = ObjectPublisher(Root())
+    wrapped_app = AuthMiddleware(app)
+    from paste.exceptions.errormiddleware import ErrorMiddleware
+    exc_wrapped_app = ErrorMiddleware(wrapped_app)
+
+簡単ですね!しかし、 *もっと* いいものが欲しいなら...
+
+::
+
+    app = ObjectPublisher(Root())
+    wrapped_app = AuthMiddleware(app)
+    from paste.evalexception import EvalException
+    exc_wrapped_app = EvalException(wrapped_app)
+
+エラーを発生させてみましょう。
+ちいさな + をクリックしてください。
+ボックスの中に何か入力してみましょう。
+
+Configuration
+=============
+
+フレームワークとアプリケーションを作成しました。
+(私が示してきたものよりもはるかにいいものになっていると確信しています。)
+これらを手でつなぎ合わせるのは、幾分粗雑と感じるかもしれません。
+
+そうでなくても、誰かが他の場所にインストールしたり、違う構成にしたりするときに、困ることでしょう。
+
+だから、アプリケーションの構成から、設定を分離しておきたいのです。
+
+What's Next?
+============
+
+まだ続きがあります, 今後構成についても話す予定です。(`Paste Deploy
+<http://pythonpaste.org/deploy/>`_ を使います)。
+そして、パッケージングやプラグインについても短い紹介ができたらいいと思います。
+そのときは、 `私のブログ <http://blog.ianbicking.org>`_ で、告知します。

File docs-source/index.rst

+.. Translations documentation master file, created by
+   sphinx-quickstart on Tue Sep 14 12:45:40 2010.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to Translations's documentation!
+========================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+

File docs/Makefile

+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD = /Users/odagiriatsushi/works/translations/bin/sphinx-build
+PAPER         =
+BUILDDIR      = /Users/odagiriatsushi/works/translations/docs
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) /Users/odagiriatsushi/works/translations/docs-source
+
+.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html      to make standalone HTML files"
+	@echo "  dirhtml   to make HTML files named index.html in directories"
+	@echo "  pickle    to make pickle files"
+	@echo "  json      to make JSON files"
+	@echo "  htmlhelp  to make HTML files and a HTML help project"
+	@echo "  qthelp    to make HTML files and a qthelp project"
+	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  changes   to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck to check all external links for integrity"
+	@echo "  doctest   to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/sphinx.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sphinx.qhc"
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+	      "run these through (pdf)latex."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."