Sphinx&Graphvizで日本語を含むグラフを出力する方法
※ 環境は以前(id:re_guzy:20101012)と同じ
基本的にはドキュメントを見ればOKだが、日本語を記述すると文字化けするので、その回避策をメモしておく。
まずはconf.pyでgraphviz拡張を有効にする。
# conf.pyを修正 extensions = ['sphinx.ext.autodoc','rst2pdf.pdfbuilder', 'sphinx.ext.graphviz']
この時点でも以下のようにすれば、日本語を使うことができる。
.. digraph:: testname node[fontname=ipag] "bar" -> "baz" -> "日本語"
ただ、毎回フォントを指定するのも面倒なので、以下のようにconf.pyに追記してしまう。
# conf.pyに追記, IPAゴシックを使う場合 graphviz_dot_args = [ '-Gfontname=ipag', '-Nfontname=ipag', '-Efontname=ipag', ]
そうすると、以下のように記述しても日本語が文字化けしません。
.. digraph:: testname graph[rankdir=LR] "bar" -> "baz" -> "日本語"
※ フォントが見つからない場合、環境変数DOTFONTPATHを指定する必要があるかも
SET DOTFONTPATH=%WINDIR%\Fonts;YOUR_FONT_DIR;
Windows環境でSphinxを使って日本語PDFを作成するメモ
参考URL
- http://sphinx-users.jp/gettingstarted/install_windows.html
- http://sphinx-users.jp/cookbook/pdf/rst2pdf.html
前提条件
easy_installで依存ライブラリもインストールされるはず。今回試したのは以下のバージョン。
- python 2.6.6
- docutils 0.7
- jinja 2.5.2
- PIL 1.1.7
- pygments 1.3.1
- reportlab 2.5
- rst2pdf 0.16
- sphinx 1.0.4
ディレクトリ構成はこんな感じ
WORK_DIR +-build ・・・ 成果物格納ディレクトリ +-fonts ・・・ フォント格納ディレクトリ +-souce ・・・ ソース格納ディレクトリ +- index.rst ・・・ ソース +- conf.py +- ja.json +- make.bat +- Makefile
日本語フォント
VLゴシックフォントとIPAフォントをダウンロードしてきて、WORK_DIR\Fontsにコピーする。C:\WINDOWS\Fontsディレクトリにインストールしてもいいが、Sphinxの設定はPythonコードなので、フォントパスを指定してあげればどこに配置しても構わないはず。
conf.py修正
参考URLのように修正すればいいが、次の2点は以下のように修正する。
- pdf_stylesheetsは、sphinxとjaのみ指定する。そうしないと余計なフォントを探しに行って、PDF作成にとても時間がかかる。
- pdf_font_pathには、先程ダウンロードしてきたフォントのコピー先を指定する。
pdf_stylesheets = ['sphinx','ja'] import os font_dir = os.path.abspath(os.path.join(os.path.split(__file__)[0], os.pardir, 'fonts')) pdf_font_path = [font_dir, 'C:\WINDOWS\Fonts'] pdf_language = "ja"
ja.json
これはほぼ参考URLのとおり。ただし、IPAフォントは*.otfではなくて*.ttfなので、そこだけ修正する。
{ "embeddedFonts" : [ [ "VL-Gothic-Regular.ttf", "VL-PGothic-Regular.ttf", "ipam.ttf", "verdanaz.ttf" ] ], "fontsAlias" : { "stdFont": "VL-PGothic-Regular", "stdBold": "VL-PGothic-Regular", "stdItalic": "VL-PGothic-Regular", "stdBoldItalic": "VL-PGothic-Regular", "stdMono": "VL-PGothic-Regular", "stdMonoBold": "VL-PGothic-Regular", "stdSanBold": "VL-PGothic-Regular", "stdSansBold": "VL-PGothic-Regular" }, "styles" : [ ["base" , { "wordWrap": "CJK", "kerning" : true }], ["literal" , { "wordWrap": "None" }] ] }
バッチファイル修正
make.batを修正して、"make pdf"でPDFを作成できるようにする。
if "%1" == "pdf" ( %SPHINXBUILD% -b pdf %ALLSPHINXOPTS% %BUILDDIR%/pdf echo. echo.Build finished. The PDF files are in %BUILDDIR%/pdf goto end )
これで一応日本語PDFが作成できるんだけども、外部リンクを貼るときターゲット定義とリンクを分割するとエラーが発生する。原因はよくわからない。
py2exeで生成するexeの名前を指定する方法
いくら検索してもpy2exeで生成するexeの名前を指定する方法が見つからなかったのでメモしておく。
キーになるのは「dest_base」。生成するexeの種類によって指定の仕方が異なるので注意。
# -*- encoding: utf-8 -*- from distutils.core import setup py2exe_options = { 'compressed': 1, 'optimize': 2, 'bundle_files': 1 } #メインスクリプトがmain.pyの場合 setup( options = { 'py2exe' : py2exe_options }, #コンソールアプリの場合、cosole=の行のコメントアウトを外す #console=[dict(script='main.py', dest_base='console_exename'),], #Windowsサービスの場合、service=の行のコメントアウトを外す #service=[dict(modules='main', dest_base='service_exename'),], )
インストールしないでPython2.6を動かしてみた
ずいぶん前にした質問を自己解決できそうなので、その手順をメモしておく。
使ったのはPython2.6.6+Windows7。コピーして試してみたのはWindowsXP。
Python2.6.6のインストール
まずはネタ元のPythonをインストール。重要なのは「Install just for me」。このオプションを選択しないと、python26.dllがインストール先ディレクトリにコピーされない。
コピー先PCでPythonが動作させるには以下のdllが必要なので、忘れずに選択すること。あとの選択はどうでもいい。以下は「C:\python26」にインストールしたものとする。
- python26.dll
- msvcr90.dll
- Microsoft.VC90.CRT.manifest
必須ライブラリのインストール
easy_install、IPythonは必須だろうから、インストールしておく。
CD /d C:\python26 python ez_setup.py CD scripts easy_install ipython easy_install pyreadline
pywin32のインストール
あるといろいろ便利なのでpywin32をインストールしておく。ただし、「easy_install pywin32」ではコピー先PCでDLLがロードできないので、ソースからインストールする。理由は不明。
このときCコンパイラを設定しておく必要があるかも。よく覚えてない。
pywin32を動作させるためには、pythoncom26.dllとpywintypes26.dllが必要なので、「C:\python26」にコピーしておく。
CD /d pywin32_source_directory python setup.py install CD /d C:\python26\Lib\site-packages\pywin32_system32 COPY pythoncom26.dll C:\python26 COPY pywintypes26.dll C:\python26
Fabricのインストール
デプロイツールFabricもあると便利なのでインストールしておく。
CD /d C:\python26\Scripts easy_install fabric
pythonのコピー
以上の作業を行った後、「C:\python26」以下のファイルをコピー先PCにコピーする。これでもpython単体は動作するが、easy_installやIPython、Fabricが動作しない。
これは「C:\python26\Scripts」以下のpyファイルに記述されているpythonのパスがおかしいため。コピー先PCでも「C:\python26」にコピーすれば動くかもしれないが、それだといまいちなので、どこにコピーしても動作するようにパスを修正する。
こんなスクリプト「fix_pythonpath.py」をコピー先ディレクトリに配置して、
# -*- encoding: utf-8 -*- # fix_pythonpath.py import glob import sys def fix_pythonpath(): """ pythonスクリプトのパスを修正します。 """ for file in glob.glob(r'python\scripts\*.py'): template = open(file, 'r') try: lines = template.readlines() finally: template.close() target = open(file, 'w') try: is_first_line = True for line in lines: if is_first_line: target.write('#!%s\n' % sys.executable) is_first_line = False else: target.write(line) finally: target.close() if __name__ == '__main__': fix_pythonpath()
こんなバッチをコピー先ディレクトリに配置する。
REM fix_pythonpath.bat SET CURRENT_DIR=%~DP0 SET PYTHONHOME=%CURRENT_DIR%python SET PATH=%PYTHONHOME%;%PYTHONHOME%\Scripts;%PATH% python fix_pythonpath.py
あとはバッチを実行してやればOK。
CD /d PYTHON_COPY_DIR fix_pythonpath.bat
これでpythonはもちろん、easy_installやIPython、Fabricも動作するようになる。
System.Windows.Forms.Button.PerformClickのWPF版
(new ButtonAutomationPeer(button).GetPattern(PatternInterface.Invoke) as IInvokeProvider).Invoke();
EnumをComboBoxに表示する。
アセンブリHogeAsmに含まれるEnum、HogeEnumをComboBoxに表示。
<UserControl x:Class="Hoge.HogeView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:hoge="clr-namespace:Hoge;assembly=HogeAsm"> <UserControl.Resources> <ObjectDataProvider x:Key="EnumList" MethodName="GetValues" ObjectType="{x:Type System:Enum}"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="hoge:HogeEnum"/> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </UserControl.Resources> <Grid> <ComboBox ItemsSource="{Binding Source={StaticResource EnumList}}" /> </Grid> </UserControl>
TracLightningでMercurialを使ってみた
サーバリプレースのついでに、自己流でセットアップしたTrac0.10からTracLightning2.3.2に移行してみた。ついでにTracをmod_wsgiで動かしてみたり、Mercurialと連携させてみたり、チケットの自動クローズとかできるようにしてみたのでメモしておく。
環境はこんな感じ。
- Windows Server 2003 R2 Standard Edition
- TracLightning 2.3.2
- mod_wsgi 2.3
- Mercurial 1.4
- TracMercurial 0.11.0.8
- MinGW 5.1.6
TracLightningをmod_wsgiで動かす
参考URL
これは参考URLのまま。
1.2つ目のURLからmod_wsgi.soをダウンロードして、C:\TracLight\CollabNetSVN\httpd\modulesにコピー
2.C:\TracLight\CollabNetSVN\httpd\conf\httpd.confの書き換え
--- a/CollabNetSVN/httpd/conf/httpd.conf Fri Nov 20 14:55:06 2009 +0900 +++ b/CollabNetSVN/httpd/conf/httpd.conf Fri Nov 20 15:05:18 2009 +0900 @@ -496,7 +496,7 @@ LoadFile "../../python/python25.dll" LoadModule authz_svn_module modules/mod_authz_svn.so LoadModule dav_svn_module modules/mod_dav_svn.so -LoadModule python_module modules/mod_python.so +#LoadModule python_module modules/mod_python.so #LoadModule fcgid_module modules/mod_fcgid.so @@ -534,14 +534,19 @@ # PythonDebug On #DefaultInitEnv TRAC_ENV_PARENT_DIR "C:\TracLight\projects\trac" -ScriptAlias /trac "C:\TracLight\CollabNetSVN\httpd\cgi-bin\trac.cgi" +#ScriptAlias /trac "C:\TracLight\CollabNetSVN\httpd\cgi-bin\trac.cgi" +LoadModule wsgi_module modules/mod_wsgi.so +WSGIScriptAlias /trac "C:/TracLight/CollabNetSVN/httpd/cgi-bin/trac.wsgi" <Location "/trac"> - SetHandler mod_python - PythonHandler trac.web.modpython_frontend - PythonOption TracEnvParentDir "C:\TracLight\projects\trac" - PythonOption TracUriRoot /trac - PythonOption PYTHON_EGG_CACHE "C:\TracLight\projects\.egg-cache" +# SetHandler mod_python +# PythonHandler trac.web.modpython_frontend +# PythonOption TracEnvParentDir "C:\TracLight\projects\trac" +# PythonOption TracUriRoot /trac +# PythonOption PYTHON_EGG_CACHE "C:\TracLight\projects\.egg-cache" + WSGIApplicationGroup %{GLOBAL} + Order deny,allow + Allow from all </Location> <Location "/svn/">
3.C:\TracLight\CollabNetSVN\httpd\cgi-bin\trac.wsgiを作成
#!C:\TracLight/python/python.exe # -*- coding: utf-8 -*- # import sys sys.stdout = sys.stderr import os os.environ['TRAC_ENV_PARENT_DIR'] = 'C:/TracLight/projects/trac' os.environ['PYTHON_EGG_CACHE'] = 'C:/TracLight/projects/.egg-cache' import trac.web.main application = trac.web.main.dispatch_request
Mercurialとの連携
参考URL
Mercurialはバイナリインストーラは使わず、easy_installでインストールする。でないと、TracMercurialを入れても「Unsupported version control system "hg"」と言われてしまう。
なので、まずはeasy_installから。ez_setup.pyをダウンロードして、コマンドラインから以下のコマンドを実行する。
python ez_setup.py
次に、Mercurialをコンパイルできるようにするため、2つ目のURLを参考にMinGWをインストール。
環境変数PATHに以下の設定を追加して、
%PATH%;C:\MinGW\bin;
C:\TracLight\python\Lib\distutilsの中に「distutils.cfg」というファイルを作成し、そのファイルに下記を記述して保存。
[build] compiler=mingw32
あとは以下のコマンドでMercurialがインストールできる。
easy_install mercurial
次はTracMercurial – The Trac Project
easy_install -UZ http://svn.edgewall.com/repos/trac/sandbox/mercurial-plugin-0.11
SVNでチェックアウトできない場合は、ソースをダウンロードして、以下のコマンドでインストールする。
python setup.py install
最後にtrac.iniを変更する。
Mercurialのリポジトリを「C:\TracLight\projects\hg」に作ることにして、「C:\TracLight\projects\hg\SampleProject」にリポジトリを作成。
--- a/projects/trac/SampleProject/conf/trac.ini Fri Nov 20 15:05:18 2009 +0900 +++ b/projects/trac/SampleProject/conf/trac.ini Fri Nov 20 16:59:36 2009 +0900 @@ -29,7 +29,8 @@ resolve.permissions = TICKET_MODIFY [trac] -repository_dir = C:\TracLight\projects/svn/SampleProject +repository_dir = C:\TracLight\projects/hg/SampleProject +repository_type = hg authz_module_name = SampleProject [mainnav] @@ -53,6 +54,7 @@ timingandestimationplugin.ticket_daemon.timetrackingticketobserver = disabled timingandestimationplugin.ticket_webui.ticketwebuiaddon = disabled timingandestimationplugin.webui.timingestimationandbillingpage = disabled +tracext.hg.* = enabled [ticket-custom] due_assign = text @@ -73,8 +75,11 @@ private_wikis = SECRET #[searchhyperestraier] #index_path = C:\TracLight\casket #replace_left = C:\TracLight\rep #url_left = / +[hg] +show_rev = yes +node_format = short
チェンジセット1がない、とエラーにはなるが、コミットすれば問題なく使えるようになる。
チケットの自動クローズ
参考URL
- MercurialでPythonのフックを実行する方法 / PythonからOutputzにPOSTする方法 - SumiTomohikoの日記
- Mercurial のウェブインタフェースを mod_wsgi にのせてみた - daily dayflower
- Mercurial 勉強中 (7) - Web 経由の push と HTTP 認証 - daily dayflower
- Mercurial 勉強中 (8) - hook を Trac と絡めて - daily dayflower
- Mercurial: "Handling repository events with hooks" を読む | Inside ASCADE
これが一番苦労した。なぜかバッチファイルはどんなものを指定しても実行してくれない。権限の関係?
悩んでても解決しないので、1個目のURLを参考に別の方法でアプローチする。
まずMercurialリポジトリをhttpで公開する。
2個目と3個目のURLを参考に、C:/TracLight/CollabNetSVN/httpd/cgi-bin/hgweb.wsgiを作成して、
import os os.environ['HGENCODING'] = 'UTF-8' import mercurial.hg as hg from mercurial.ui import ui from mercurial.hgweb.hgweb_mod import hgweb from mercurial.hgweb.hgwebdir_mod import hgwebdir from mercurial.hgweb.request import wsgiapplication def listdir_dironly(base_dir): results = [] # prepare for failure for root, dirs, files in os.walk(base_dir): results = map(lambda d: os.path.join(root, d), dirs) dirs[:] = [] results.sort() return results def get_repo_for_path(path): return hg.repository(ui(interactive=False, report_untrusted=False), path=path) def isrepo(path): if False: # too redundant try: get_repo_for_path(path) return True except hg.RepoError: return False else: return os.path.isdir(os.path.join(path, '.hg')) def make_hgweb_maker(path): return lambda: hgweb(path, os.path.split(path)[1]) #return lambda: hgweb(get_repo_for_path(path)) def make_hgwebdir_maker(path): dirs = listdir_dironly(path) repos = [(os.path.split(dir)[1], dir) for dir in dirs] return lambda: hgwebdir(repos) def hgweb_wsgiapp(path): if isrepo(path): return wsgiapplication(make_hgweb_maker(path)) else: return wsgiapplication(make_hgwebdir_maker(path)) # for WSGI def application(environ, start_response): def filter_headers(status, response_headers): # stringify header content headers = [(key, str(value)) for key, value in response_headers] return start_response(status, headers) def error_dialog(message): headers = [('Content-Type', 'text/plain'), ('Content-Length', str(len(message)))] start_response('500 Internal Server Error', headers) return [message] if 'hgweb.reposdir' in environ: reposdir = environ['hgweb.reposdir'] else: return error_dialog("You must specify 'hgweb.reposdir' environment") wsgiapp = hgweb_wsgiapp(reposdir) return wsgiapp(environ, filter_headers) # for CGI if os.environ.get('GATEWAY_INTERFACE', '').startswith('CGI/'): import cgitb cgitb.enable() import mercurial.hgweb.wsgicgi as wsgicgi wsgicgi.launch(hgweb_wsgiapp('/path/to/repos'))
さらにhttpd.confを修正する。この時点でHTTP経由でリポジトリが参照できるはず。
--- a/CollabNetSVN/httpd/conf/httpd.conf Fri Nov 20 16:59:36 2009 +0900 +++ b/CollabNetSVN/httpd/conf/httpd.conf Fri Nov 20 17:30:12 2009 +0900 @@ -588,3 +588,19 @@ ProxyPass http://127.0.0.1:8010/hudson ProxyPassReverse http://127.0.0.1:8010/hudson </Location> + +WSGIScriptAlias /hg "C:/TracLight/CollabNetSVN/httpd/cgi-bin/hgweb.wsgi" + +<Location "/hg"> + WSGIApplicationGroup %{GLOBAL} + SetEnv hgweb.reposdir "C:/TracLight/projects/hg/" + Order deny,allow + Allow from all + + AuthType Digest + AuthName trac + AuthUserFile "C:\TracLight\projects\trac.htdigest" + <LimitExcept GET PROPFIND OPTIONS REPORT> + Require valid-user + </LimitExcept> +</Location>
次に4個目のURLを参考に、C:\TracLight\python\Lib\site-packages\hg_post_commit.pyを作成する。これは複数リポジトリがあってもいいように、少し修正してある。
# -*- encoding: utf-8 -*- hook_script = 'C:/TracLight/python-lib/trac/contrib/trac-post-commit-hook' # style:: 'short', 'long', or 'number' changeset_id_style = 'short' import os def invoke_trac_hook(trac_env, rev): def _make_smart_rev(trac_env, rev): if changeset_id_style == 'long': return rev else: import trac.env env = trac.env.open_environment(trac_env) # instance of mercurial.hg.repository repo = env.get_repository().repo ctx = repo.changectx(rev) if changeset_id_style == 'short': import mercurial.node return mercurial.node.short(ctx.node()) else: # 'number' return str(ctx.rev()) smart_rev = _make_smart_rev(trac_env, rev) f = open(hook_script, 'r') try: import imp ext = os.path.splitext(hook_script)[1] m = imp.load_module('trac_hook', f, f.name, (ext, f.mode, imp.PY_SOURCE)) m.CommitHook(project=trac_env, rev=smart_rev) finally: f.close() def hook(ui, repo, **kwargs): hg_dir, _ = os.path.split(repo.path) hg_root_dir, project_name = os.path.split(hg_dir) trac_dir = os.path.join(os.path.join(hg_root_dir, os.path.pardir, 'trac', project_name)) if 'PYTHON_EGG_CACHE' not in os.environ: os.environ['PYTHON_EGG_CACHE'] = os.path.join(trac_dir, '.egg-cache') invoke_trac_hook(trac_dir, kwargs.get('node'))
最後に「C:\TracLight\projects\hg\SampleProject\.hg\hgrc」を作成して、上記のスクリプトを指定する。
[hooks] incoming.trac = python:hg_post_commit.hook [web] push_ssl = false allow_push = * deny_push = unauthenticated_user
あとはSVNのときと同じようにコミットしてpushすれば、チケットが自動クローズされる。