SyntaxHighlighter

2018年6月26日火曜日

Single Binary StacklessPython 3.6.4 L8 リリース

Single Binary StacklessPython 3.6.4 L8 リリース

業務の効率化や Python インタプリタの勉強も兼ねて、 StacklessPython を 1 バイナリ化していましたが、バージョン L8 まできました。

GitHub のリリースページからダウンロードできます。

今回は、主に以下の変更をしました。

  • tkinter のサポート
  • EXE 化の実験的サポート
  • Windows Subsystem 版のサポート

tkinter のサポート

これまでに Python の標準ライブラリは、ほぼすべてサポートしていましたが、 tkinter はいくつかの理由でサポートしていませんでした。

tkinter をサポートし、1 バイナリで実行するには、 tcl/tk のライブラリを静的にリンクする必要があります。
また、 tcl/tk は、いくつかの *.tcl ファイルを必要とするので、こちらについても対応する必要があります。

静的リンクについては、 nmake -f makefile.vc core OPTS=static のように OPTS として static を指定すれば、静的リンク版をビルドできるので、こちらを使うことになります。

一方で、*.tcl ファイルの抱き込みについては、やや面倒です。

*.tcl ファイルの抱き込み

tcl では、Tcl_Filesystem という構造体で、複数のファイルシステムを持つことができます。
これは一言で言うと Python の path_hooks に相当するものです。
今回は embeddedFilesystem というファイルシステムを作成し、 embeddedfs:/tcl8.6/init.tcl のように embeddedfs:/ で始まる仮想的なパスが指定された場合に、バイナリの中に保持しているファイルの中身を返すようにしています。

詳しくは tclEmbeddedFilesystem.c を参照してください。

EXE 化の実験的サポート

せっかくなので、おまけの機能として EXE 化の機能を付けてみました。
なお、元々、標準ライブラリ外の機能は考慮していないので、py2exe や PyInstaller の代わりには使えません。あくまで、標準ライブラリだけを使って書けるスクリプトの EXE 化ができます。

例えば下記のように、 tk でウィンドウを作成し、クリックでカウントアップするだけのプログラムを EXE 化してみます。

今回の Single Binary StacklessPython では、上記のように tkinter を使うような場合も、実行することができます。

これを、単一の EXE にするには、下記のようにします。
ただし、これはまだ実験的な機能なので、将来は仕様を変更するかもしれません。

上記を実行すると sample.exe が生成されます。

サイズは 14MB ぐらいになりますが、テンポラリディレクトリにファイルを展開したりはしないので、かなり高速に実行されます。

Windows Subsystem 版のサポート

今回から pythonw.exe のように、コンソール画面が表示されないバイナリを作っておきました。

こちらは、主に GUI を使うスクリプトを EXE 化する際に使うと便利です。

Python, tcl/tk の実装の勉強にもなり、 AppVeyor の利用の勉強にもなりましたが、すべての標準ライブラリを 1 バイナリに収めたので、そろそろ終了にする予定です。

2018年6月13日水曜日

Single Binary 版の Stackless Python 3.6.4

Single Binary 版の Stackless Python 3.6.4

Stackless Python が 3.6.4 対応されていたので、 1 バイナリ化した Stackless Python も対応してみました。

GitHub のページから、ダウンロードしてご利用ください。

1 バイナリ化した Stackless Python

以前に Stackless Python 2.7 を 1 バイナリ化しましたがその当時の変更を Python 3.6 に対応させることになります。
今回は、その際の対応と、そもそも 1 バイナリ化した Stackless Python はどういうものかについて、まとめようと思います。

1 バイナリ化した Stackless Python 作成の目的

業務の都合上、「種々の PC 実機上で簡単に Python を実行したい」という動機がありました。
それに加えて、 pausable unittest を実行したかったので、通常の Python ではなく Stackless Python を使うことにしました。

また、極力、通常の Python と比べて、実行速度が遅くならないようにしたいということも考えていました。
前に Ruby を OCRA で固めたときは、実行前の展開にやや時間がかかるのがストレスだったので、今回はそういったことがないようにしたいと思っていました。

1 バイナリ化した Stackless Python の変更点

デフォルトの Stackless Python から以下の変更を加えました。

  • プログラム引数の変更
  • embeddedimport の実装
  • 3rd party ライブラリの同梱
  • その他の小変更

プログラム引数の変更

1 バイナリ化した Stackless Python は、引数の意味を二つだけ変更してあります。

  • -B: この引数は意味が逆になっており、-B が存在しないときに、 *.pyc ファイルを作成しないようになっています。
  • -E: この引数も意味が逆になっており、-E が存在しないときに、環境変数を参照しないようになっています。

これらの変更は、いずれも未知の環境で動作しやすいようにしておくためです。
時刻が正しくない複数の実機で実行した場合や、他に Python の処理系がインストールされていた場合にも、正しく動作させるためです。

embeddedimport の実装

通常、 Python の import 文は、 sys.path に登録されたパスを順に探し、その中から外部モジュールをロードします。
また、 sys.path には python.zipも 登録されており、 ZIP ファイルの中もサーチの対象になっています。
この ZIP ファイルからのロードは、 zipimport というモジュールが担っています。

今回は、「一つのバイナリにしたい」という目標があったので、 zipimport を参考にして、 embeddedimport を作り、実装しています。

挙動の概要としては、以下のようになります。

  1. ビルド時に、 Lib 以下の *.py ファイルをすべて C 言語の文字列に変換して、 python のバイナリに組み込んでおきます。
  2. 実行時には、 sys.path に C:/path_to/python.exe のように python.exe のフルパスを登録しておきます。また、 sys.path_hooks に embeddedimporter モジュールを登録しておきます。
  3. これにより、 import pickle などが処理される際に embeddedimporter によってモジュールのインポートが試みられます。
  4. embeddedimporter では、自身が保持している *.py ファイルの中から指定されたファイルを探し、それを実行します。

3rd party ライブラリの同梱

快適に使えるように、いくつかのライブラリを同梱してあります。

  • comtypes
  • pycodestyle
  • pyflakes
  • pyreadline
  • PyYAML with libyaml

PyYAML に関しては、 libyaml をビルドしておき、 C 言語のサポートがあった方がずっと速いので、そのようにしてみました。

一点、注意としては、 libyaml とのブリッジライブラリである _yaml は、 Cython 形式になっており、 C 言語としてビルドするには前処理が必要でした。
Stackless Python の場合、 Fast Calll 時の関数呼び出しの処理が変更されているので、 CYTHON_FAST_PYCALL を 0 に設定し、 _yaml から Fast Call させないようにすることが必要でした。

その他の小変更

プログラムの引数を変更した関係で、いくつかのテストを変更しました。 -E を使っているテストは非常に多かったので、その辺りを中心に変更しました。

また、 C 言語で書かれた拡張ライブラリ *.pyd を、静的に Python にリンクするために、ビルド方法や config.c でのビルトインモジュールの定義部分を変更しました。

私の業務の都合上、 XML の属性をソートしたくなかったので、 xml.etree.ElementTree の出力部分に少し手を加えました。
具体的には ElementTree.write に sort_attrib=True というキーワード引数を追加し、ソートを制御できるようにしておきました。

これらの対応を行い、テストがほぼ通ったので、ついにリリースになりました。
Windpws PE 上での作業や、多数のテスト実機上で Python を走らせる必要がある場合などに、ご利用いただければと思います。

2018年3月8日木曜日

Windows 上で一時的に Python を使って作業する際に使っているバッチファイル

Windows 上で一時的に Python を使って作業する際に使っているバッチファイル

私は、仕事でクリーンな (OS 展開直後の) Windows 実機や Windows PE 上で、Python を用いて作業をすることがしばしばあります。
今回は、その際によく使っているスクリプトを備忘録としてまとめておきます。

いずれも、 Python の -x オプションを使って、バッチファイル先頭行の goto 文をスキップしています。

1バイナリの Python

前提として、1バイナリ化した Python を使います。

以前に書いたように、ほぼすべての標準ライブラリを含んだ StacklessPython を、単一の EXE ファイルをコピーするだけで動作するようにしてあります。
こういった用途のために作ったので、インストールが不要かつコピーするだけで使えるようにしました。

管理者権限で実行する Python スクリプト

下記のようなバッチファイルを用意し、print("hoge") 部分を好きな Python スクリプトに変更すれば、ダブルクリックするだけで、管理者権限の Python スクリプトとして実行することができます。
なお、同じディレクトリに python.exe が必要です。

readline を有効にした状態で Python インタプリタを立ち上げるスクリプト

こちらも、下記のようなバッチファイルを用意し、ダブルクリックすれば、 Python のインタプリタが立ち上がります。
pyreadline を使っているので、 Ctrl-f などのキーバインドや、補完、ヒストリ保存もできます。

作業の内容によっては使えると思いますので、置いておきます。

2017年12月16日土曜日

Outlook のキーワード強調表示用のフォントを作成する

Outlook のキーワード強調表示用のフォントを作成する

LigatureYourName

前回の Outlook でキーワードハイライトを実現する方法の続きです。

LigatureYourName というサイトでフォントを作成することができます。
せっかくなので、 Heroku で WEB サービスとして作成してみました。

フォントの情報

ベースフォント
ベースとなるフォントは、源真ゴシックです。
ライセンス
源真ゴシックに準じ、 SIL Open Font License 1.1 のもとに使用することができます。

その他

  • アルファベットなど、日本語以外の文字ではうまく強調表示されないことがあるようです。
    アプリケーションの描画方法に依存するようですが、理由をご存知でしたら教えてください。
  • 種類は、デフォルトで OpenType (PostScript) です。
    これは、 Windows10 の Creators Update より前では、TrueType 形式のフォントは汚く表示されることがあるためです。
    TrueType 形式が必要な場合、「詳細」欄で選択することができます。
  • このフォントの利用により生じたいかなる損害についても、一切責任を負いません。
    ご自身の責任の範囲でお使いください。

次回は、 LigatureYourName のサイトを作った際の技術的な内容について、まとめる予定です。

Outlook で本文中の固定キーワードを強調表示する方法

Outlook で本文中の固定キーワードを強調表示する方法

はじめに

Outlook は広く使われているメーラーの一つではないかと思いますが、なぜかキーワードハイライトができないようです。
例えば、自分の名前を本文中で常にハイライトしたいのですが、私が探した限り、そういった方法は見つかりませんでした。

以前に使ったことがある Becky! や Thunderbird では標準機能やプラグインでサポートされていますので、不便に感じていました。

今回は Outlook で固定キーワードを強調表示する方法についてまとめます。

キーワードハイライトの仕組み

専用フォントによるハイライト

Outlook 用に、専用のフォントを入れ、そのフォントで表示することで実現します。
そのフォントでは、あらかじめ強調したいキーワードの文字だけを太字にしておくなどすることで、疑似的にキーワードハイライトすることができます。
例えば、「ハイライト」というキーワードを白黒反転で強調するような場合、以下のようになります。

このように、あらかじめ指定した「ハイライト」が指定した白黒反転で強調表示されています。
サンプルページで実際の挙動を確認できます。

リガチャ (合字) によるキーワード指定

前掲した例を見ると分かりますが、「ライト」は強調表示されていません。
これは、フォントの「リガチャ (合字)」機能を使って実現しているためです。

Wikipedia の合字ページを見ると分かりますが、リガチャとは欧文などで特定の並びの文字に専用のフォントを指定できるようにする機能です。
よく目にする例では、ff の並びに対し、二つの f がいい具合に合わさったものがあります。

このフォントの機能を活用し、日本語でも特定の並びの文字に対してリガチャを作成することで、疑似的なキーワードハイライトを実現することができます。
今回の例では、「ハイライト」を白黒反転したものを一つのグリフ (字形) として作成し、それを「ハイライト」の文字の並びに対して使うように、リガチャ指定しています。
こういった仕組みのため、部分文字列の「ライト」が強調表示されることはありません。

制限事項

この仕組みでキーワードハイライトを実現する場合、以下のような制限事項があります。

強調するキーワードを動的に変更できない
強調するキーワードを変更する場合、フォントを生成しなおす必要があるので、動的にキーワードを変更することはできません。
リガチャをサポートしている Outlook でのみ使える
具体的には Outlook 2010 以降が必要です。
(Outlook で使う場合) HTML メールの強調には使えない
テキストメールの読み書きに対してしか使えません。
改行がはさまるとリガチャにならない
改行が挟まった場合は、通常の文字として表示されます。

次回は、実際にフォントを作成する方法についてまとめます。

2017年10月27日金曜日

Nyagos の拡張 (主に Subversion 用 Lua スクリプト)

Nyagos の拡張 (主に Subversion 用 Lua スクリプト)

前回は Nyagos を tcsh 風に使うようにするための変更についてまとめました。
今回は、それに加えてもう少し Subversion まわりについて拡張してみました。

できること

作成した vcs_info.lua で、以下のことができます。

  • svn ls https://github.com/masamitsu-murase/nyagos.git/trunk/[Tab] のように、 svn で始まる場合に URL のパスに対しても補完することができます。
  • VcsInfo.box_svn_revisions(path) のように呼ぶことで、 C-x C-g の git のリビジョン選択のように、 Subversion のリビジョンを選択することができます。
  • VcsInfo.check_vcs_branch() で、現在のパスが svn, git, hg のいずれかを判別し、返してくれます。
    また、 git, hg の場合はブランチ名を、 svn の場合は親ディレクトリの名前を、二つ目の戻り値として返してくれます。

必要なファイルは nyagos.d/catalog/vcs_info.lua として GitHub に置いてあります。
このファイルを nyagos.d/catalog 以下に置き、 .nyagos でいくつか設定をします。

Subversion の URL の補完

この機能を使うには、 vcs_info.lua を .nyagos で use するだけです。
.nyagos の例を見てください。

このスクリプトを使うと、svn で始まるときに限り、後続の URL を補完してくれます。

svn ls コマンドで、リポジトリのディレクトリを見ながら補完するので、環境によってはやや遅いですが、私としてはそれなりに快適に使えています。

また、デフォルトでは直前の補完結果を 10秒間はキャッシュしていますので、連続で Tab を押したときは軽快に動くようになっています。

Subversion のリビジョンの選択

コマンドラインでマージをする際に、マージ対象のリビジョンを手で入力するのは面倒です。
git の場合は、 C-x C-g でログを表示し、ハッシュ値を入力することができますが、これと同じようなことができることを目指しました。

この機能を使う場合、 box.lua のコードを参考に、以下のようなコードを .nyagos に追加する必要があります。

上記のように、 VcsInfo.find_svn_path で現在のコマンドライン入力の中から URL らしきものを探し、 VcsInfo.box_svn_revisions でリビジョンを選択することができます。

git, svn, hg のブランチ名の取得

VcsInfo.check_vcs_branch を呼ぶことで、現在のディレクトリのブランチ名を取得することができます。

以下のようなルールでブランチ名を取得しています。

git, hg
git rev-parse --abbrev-ref HEAD や hg branch でブランチ名を取得しています。
svn
現在のディレクトリを含むチェックアウトツリーのルートディレクトリを探し、その一つ上のディレクトリ名を取得します。
例えば、http://example.com/trunk をチェックアウトしたディレクトリ以下なら、trunk を返します。
同様に、http://example.com/branches/feature_a をチェックアウトしたディレクトリ以下なら、 feature_a を返します。

私は、この機能を用いて以下のようにプロンプトを表示しています。

このスクリプトだと、以下のようにプロンプトが表示されます。

もちろん、 Subversion のディレクトリ名が日本語を含む場合でも、適切に動作します。

Nyagos は Lua で拡張できるおかげで、割と楽に拡張することができました。

2017年10月1日日曜日

NYAGOS を Windows で tcsh 風に使う

NYAGOS を Windows で tcsh 風に使う

私はこれまで Windows 上で tcsh をシェルとして使っていました。しかし、 RS2 にアップデートしたあたりから、なぜかクラッシュすることが多くなってきたので、代替のシェルを探していました。
パスを Windows 風にも使えることと、慣れてしまった tcsh 風のキーバインドをサポートしていることを条件に、いろいろなシェルを探してみました。

その結果、 tcsh から NYAGOS に変更してみることにしました。
ここでは、 tcsh に似せるために標準の NYAGOS に追加した、いくつかの変更についてまとめます。

NYAGOS とは

NYAGOS は zetamatta さんによって Windows 向けに開発されているシェルです。
本体は Golang で書かれており、 Lua スクリプトで拡張できるように設計されています。
また、日本語にもしっかりと対応されています。

素晴らしいシェルを公開していただき、ありがとうございます。

Windows で使えるシェルとしては、NYAGOS 以外にもたくさんのものがありますが、先に挙げた条件に加え、「Cygwin などの、 Windows ネイティブな環境でないものは使いたくない」、「日本語にきちんと対応しているものがよい」、「Golang を勉強したい」という理由により、 NYAGOS を使おうと思いました。

使い方

必要なファイル類は、 GitHub の私の Fork の tcsh_style のブランチにあります。

公式のリリースに比べ、上記のブランチでは nyagos.d/catalog の下の以下のファイルが追加されています。

case_sensitive_completion.lua

大文字と小文字を区別して補完するためのスクリプトです。

dollar_env.lua

環境変数を $TEMP 形式で (ある程度) 使えるようにするためのスクリプトです。
また、 echo $TEM[Tab] のような場合に、$TEMP と補完もしてくれます。
ただし、 $TEMP/[Tab] で Temp ディレクトリ以下のファイルを補完してくれたりはしません。

emphasize_completion.lua

補完候補の最初の一文字を強調表示するスクリプトです。
例えば、フォルダに fileA.txt, fileB.txt, fileC.txt がある場合、 ls file[Tab] と入力すると、 fileA.txt, fileB.txt, fileC.txt のように、次に入力するべき文字が強調されて表示されます。

tcsh_like_keybind.lua

tcsh の下記のキーバインドを実現します。

Alt+/
現在入力中の単語を、過去の入力データをもとに補完します。
Alt+p, Alt+n
現在入力中のコマンドを、過去の入力コマンドをもとに補完します。
Alt+BackSpace
カーソルより左の単語を一つ消去します。
Alt+d
カーソルより右の単語を一つ消去します。

なお、完全に tcsh と同一な動きをするわけではありませんし、それを目指しているわけでもありません。
日本語には対応しているつもりです。

.nyagos ファイルへの変更

上記の変更を有効にするために、 .nyagos ファイルに下記のような変更をします。

上記のように、末尾で use により先ほどのファイルを読み込みます。これで、それぞれの機能が有効になります。
なお、 dollar_env に関しては、 completion_hook の対応がやや古い状態なので、他のファイルより先に読み込んでおくとよいです。
また、 tcsh_like_keybind に関しては、内部で nyagos.prompt の書き換えを行っているので、 nyagos.prompt よりも後で読み込む必要があります。

これらの変更により、快適に Windows 上で tcsh ライクなシェル操作を実現できました。