wxHTMLのメモ

#!/usr/bin/local/python
# -*- coding: utf-8 -*-
import sys
import os
import wx
import wx.html
from wx import xrc

class MyApp(wx.App):
    def OnInit(self):
        self.frame = wx.Frame(None, -1, "test")

        sizer = wx.BoxSizer( wx.VERTICAL )
        self.main_wnd = wx.html.HtmlWindow( self.frame, wx.ID_ANY)
        sizer.Add(self.main_wnd, 1, wx.ALL|wx.EXPAND, 5)
        self.frame.SetSizer( sizer)
        self.frame.Layout()

        self.main_wnd.SetPage("<h1>ERRO</h1>")

        self.frame.Show()
        return True


    def OnExit(self):
        pass
    


if __name__ == "__main__":
    app = MyApp()
    app.MainLoop()

RGB->L*a*b*変換

とりあえずメモ

RGB2XYZ_D65 = (
    0.412453, 0.357580, 0.180423,
    0.212671, 0.715160, 0.072169,
    0.019334, 0.119193, 0.950227
)

D65 = ( 0.950456, 1., 1.088754 );

_coff = (
     RGB2XYZ_D65[0]*(1.0/D65[0]),RGB2XYZ_D65[1]*(1.0/D65[0]),RGB2XYZ_D65[2]*(1.0/D65[0]),
     RGB2XYZ_D65[3]*(1.0/D65[1]),RGB2XYZ_D65[4]*(1.0/D65[1]),RGB2XYZ_D65[5]*(1.0/D65[1]),
     RGB2XYZ_D65[6]*(1.0/D65[2]),RGB2XYZ_D65[7]*(1.0/D65[2]),RGB2XYZ_D65[8]*(1.0/D65[2]),
)

def _conv_func(v):
    if v > 0.008856:
        return v ** (1.0 / 3.0)
    else:
        return (903.3 * v + 16 ) / 116.0

def rgb2lab(rgb):
    rgb = [x/255.0 for x in rgb]
    xyz = (
        rgb[0]*_coff[0] + rgb[1]*_coff[1] + rgb[2]*_coff[2],
        rgb[0]*_coff[3] + rgb[1]*_coff[4] + rgb[2]*_coff[5],
        rgb[0]*_coff[6] + rgb[1]*_coff[7] + rgb[2]*_coff[8],
    )

    fX, fY, fZ = map(_conv_func, xyz) 
    L = 116.*fY - 16.;
    a = 500.*(fX - fY);
    b = 200.*(fY - fZ);
    return (L, a, b)

JavaScriptでデフォルト引数を使う

最近、JavaScriptを使うことになったので勉強中。
デフォルト引数が使いたいなと思いググったところ、下のコードが沢山ヒットする。

def test(a) {
    a = a || デフォルト値
    ...
}

え、これってデフォルト引数が0やFalseの場合ダメだよね・・・?
正しくはこうだと思うんだが・・・

def test(a) {
    if(a === undefined) a = デフォルト値;
    ...
}

「a == undefined」ではなく「a === undefined」なので注意。

JavaScriptに詳しい方で、修正がありましたらご指摘ください。

[追記]
コメントから指摘がありました。
上記の方法だとundefinedが上書きされている可能性があるので、厳密に求めたい場合は以下の方法が良さそうです。

def test(a) {
    if(typeof a === 'undefined') a = デフォルト値;
    ...
}

上記の方法からタイプ量もそんなに増えない為、かなり良い方法だと思います。
edvakfさん、ありがとうございました。

Windowsを再起動/終了/スリープ/休止状態にする

再起動/終了

import os

#Windowsの再起動
os.system('shutdown -r -f')

#Windowsの終了
os.system('shutdown -s -f')

スリープ/休止状態

import ctypes

#Windowsのスリープ
ctypes.windll.PowrProf.SetSuspendState(0, 1, 0)

#Windowsの休止
ctypes.windll.PowrProf.SetSuspendState(1, 1, 0)

文字列のcsvを解析する方法

csvモジュールはcsvファイルしか解析できないと思われがちだが、メモリ上のcsvを解析する事も可能。
一番簡単な方法は、以下の通り。

import csv
for row in csv.reader(['one,two,three']):
    print row
# ['one', 'two', 'three']

複数行の文字列も解析可能。

import csv

csv_str = """
one,two,three
four,five,six
"""

for row in csv.reader(csv_str.strip().splitlines()):
    print row
#['one', 'two', 'three']
#['four', 'five', 'six']

但し上の方法だと、フィールドが複数行の場合は改行が削除されてしまう。
改行を保持したまま解析したい場合はStringIOを使う。

import csv

csv_str = """
one,two,three
four,five,"six
seven"
"""

for row in csv.reader(csv_str.strip().splitlines()):
    print row
# Bad
#['one', 'two', 'three']
#['four', 'five', 'sixseven']

#改行を保持したい場合は、StringIOを使う
import StringIO

for row in csv.reader(StringIO.StringIO(csv_str.strip())):
    print row
# Good
#['one', 'two', 'three']
#['four', 'five', 'six\nseven']

小技

Excelからセルをコピペするとタブ区切りになる。
タブ区切りに対応する場合はcsv.reader()の第2引数にcsv.excel_tabを指定すると簡単。

import csv
import StringIO

csv_str = """
one\ttwo\tthree
four\tfive\tsix
"""

for row in csv.reader(StringIO.StringIO(csv_str.strip()), csv.excel_tab):
    print row

おまけ

csv.Sniffer.sniff()を使うと、csvの区切り文字などをpythonが推測してくれる。
外部のCSVの形式が不定の場合に使えるかも。

import csv
import StringIO

csv_str = """
one\ttwo\tthree
four\tfive\tsix
"""

io = StringIO.StringIO(csv_str.strip())

try:
    #サンプルを元に区切り文字を推測する
    dialect = csv.Sniffer().sniff(io.readline())
except:
    dialect = csv.excel

io.seek(0)
for row in csv.reader(io, dialect):
    print row
#タブ区切りだと推測成功
#['one', 'two', 'three']
#['four', 'five', 'sixseven']

区切り文字がある程度決まっている場合は、sniff()の第2引数に区切り文字の候補を与えてあげると精度が上がる。

# 区切り文字がタブかカンマの2択の場合は以下の通り
dialect = csv.Sniffer().sniff(io.readline(), "\t,")

ヘッダ行があるか推測するcsv.Sniffer.has_header()もあるらしい。

注意点

マニュアルより、Unicodeはサポートしていないそうです。

ノート
このバージョンの csv モジュールは Unicode 入力をサポートしていません。また、現在のところ、 ASCII NUL 文字に関連したいくつかの問題があります。従って、安全を期すには、全ての入力を UTF-8 または印字可能な ASCII にしなければなりません。これについては 使用例 節の例を参照してください。これらの制限は将来取り去られることになっています。

SCons入門(3)

SCons入門(1) - Pashango’s Blog
SCons入門(2) - Pashango’s Blog

ファイル/ディレクトリ操作「Copy,Move,Delete,Touch,Mkdir,Chmod」

SConsではファイル/ディレクトリ操作用に以下の関数が用意されている。

Copy(dst, src) ファイル/ディレクトリのコピー
Move(dst, src) ファイル/ディレクトリの移動
Delete(tgt) ファイル/ディレクトリの削除
Touch(tgt) タイムスタンプの更新
Mkdir(tgt) ディレクトリの作成
Chmod(tgt, prm) パーミッションの変更

これらの関数は単独では使用できない、Commandなどのアクション部分に組み込んで初めて動作する。
SConstructのサンプルは以下のとおり。

Command("file.out", "file.in",
        [
          Mkdir("tmpdir"),
          Copy("tmpdir/main.c", "main.c"),
          "mycommand $SOURCE $TARGET",
          Move("$TARGET", "tmpdir/$TARGET"),
          Delete("tmpdir"),
          Touch("$TARGET"),
          Chmod("$TARGET", 0755),
        ])

実行結果は以下のとおり、テンポラリデイレクトリの生成/削除を行い、最後にパーミッションを変更している。

>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
Mkdir("tmpdir")
Copy("tmpdir/foo.in", "foo.in")
mycommad foo.in foo.out
Move("foo.out", "tmpdir/foo.out")
Delete("tmpdir")
Touch("foo.out")
Chmod("foo.out", 0755)
scons: done building targets.

アクションを実行する「Execute」

必要なディレクトリをビルド前に作成したい状況があるが「Mkdir」は単独では使用できない、そんな時は「Execute」と「Mkdir」を組み合わせて使う。

if Execute(Mkdir('output_dir')):
    # ディレクトリの作成に失敗したらExit
    Exit(1)

これで、ビルド前にあらかじめディレクトリを作成してくれる。

ヒエラルキービルドをする「SConscript」

大規模なプロジェクトになると、各ディレクトリ毎にSConstructを分けたくなるかもしれない。
そんな時は「SConscript」を使えば、他のディレクトリのビルドを制御する事が出来る。

SConscript(['drivers/display/SConscript',
            'drivers/mouse/SConscript',
            'parser/SConscript',
            'utilities/SConscript'])

SCons入門(2)

SCons入門(1) - Pashango’s Blog

ファイル更新チェックの方法を変更する「Decider」

SConsでは、ファイルの更新チェックに標準でMD5を使用する。
そのため、タイムスタンプが異なっていても、ファイル内容が同じであれば不要なビルドを避けてくれる。


MD5で更新チェックは非常に便利なのだが、映像ファイルなどのファイルサイズが大きいものには不向きである。
そこでSConsでは、ファイルの更新チェック方法を「Decider」で設定することができる。

以下、Deciderの設定例。

#MD5で更新チェック(標準)
Decider('MD5')

#タイムスタンプが新しければ更新
Decider('timestamp-newer')
Decider('make')              #timestamp-newerの別名

#タイムスタンプが異なっていれば更新
Decider('timestamp-match')

#MD5が変更、または、タイムスタンプが新しければ更新
Decider('MD5-timestamp')

もちろん、カスタムの更新チェック関数を設定することも可能。

Program('hello.c')
def decide_if_changed(dependency, target, prev_ni):
    if self.get_timestamp() != prev_ni.timestamp:
        dep = str(dependency)
        tgt = str(target)
        if specific_part_of_file_has_changed(dep, tgt):
            return True
   return False
Decider(decide_if_changed)

ここで気をつけなければいけないのは、最後に記述された「Decider」が有効になるということ。
以下のようにa.txtは「make」で更新チェック、b.txtは「MD5」で更新チェックしようとしても、後に書かれたDeciderが有効になってしまい2つのファイルともMD5で更新チェックされてしまう。

env = Environment(ENV = os.environ)

env.Decider('make')
env.Command("a.out", "a.txt", "python my_convert.py $SOURCE $TARGET")

env.Decider('MD5')
env.Command("b.out", "b.txt", "python my_convert.py $SOURCE $TARGET")
#a.txtもb.txtもMD5で更新チェックされてしまう!

複数のDeciderを有効にしたい場合は、Environmentを分ける必要がある。

env_make = Environment(ENV = os.environ)
env_md5  = env_make.Clone()

env_make.Decider('make')
env_md5.Decider('MD5')

env_make.Command("a.out", "a.txt", "python my_convert.py $SOURCE $TARGET")
env_md5.Command("b.out", "b.txt", "python my_convert.py $SOURCE $TARGET")

出力ファイルをインストールする「Install,InstallAs」

出力ファイルを、指定ディレクトリにコピーするには「Install」または「InstallAs」を使う。
すでにコピー先にファイルがある場合、タイムスタンプなどを考慮して必要があれば上書きする。

#出力ファイルを/usr/binにインストール(コピー)する
output = Program('cmd.c')
Install('/usr/bin', output)

#複数ファイルのインストールも可能
Install('/usr/bin', ['cmd_a', 'cmd_b'])

#ファイル名を変えながらインストールする場合はInstallAsを使う
InstallAs('/usr/bin/new_cmd', 'cmd')

標準のビルドターゲットを設定する「Default」

SConsでビルドターゲットを省略した場合、標準のビルドターゲットがビルドされる。
「Default」で標準のビルドターゲットを設定する事が出来る。
以下、Sconstructの記述例、「hello.c」と「goodbye.c」の2つのタスクがあるが、「hello.c」を標準のビルドターゲットにする。

hello = Program('hello.c')
Program('goodbye.c')
Default(hello)

コマンドラインから「scons」と打つと、標準のビルドターゲット「hello.c」だけがビルドされる。
「goodbye.c」は明示的にビルドターゲットを指定しない限り、ビルドされなくなる。

> scons -Q
cc -c -o hello.o hello.c
cc -o hello hello.o
> scons -Q
scons: `hello' is up to date.
> scons -Q goodbye
cc -c -o goodbye.o goodbye.c
cc -o goodbye goodbye.o

クリーンされるファイルの制御「Clean,NoClean」

コマンドラインで「scons -c」と打つと、ビルドファイルがクリーンアップされる。
この時、SConsが削除すべきファイルを自動的に調べてくれるのだが、「Clean」で削除するファイル/ディレクトリを追加できる。

Cleanの第1引数は、削除対象ファイルと関連があるビルドターゲット。
第2引数は、追加する削除対象ファイルとなる。

以下の例では、ビルド時に出るlogファイルをクリーン時に削除する例。

a = Program('a.c')
b = Program('b.c')

Clean(a, 'a.log')
Clean(b, 'b.log')

コマンドラインから「scons -c」を打つと、logファイルも削除される。

> scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed a
Removed a.log
Removed b
Removed b.log
scons: done cleaning targets.

#ターゲット指定も可能(この場合はbとb.logは削除されない)
> scons -c a
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed a
Removed a.log
scons: done cleaning targets.


Clearの第1引数に'all'を指定すれば、ビルドターゲット省略時にクリーンされるようになる。
また「Glob」を使えば、ワイルドカードでファイルを指定できる。

#scons -c の時、workディレクトリも削除する
Clean('all', 'work')

#logファイルをすべて削除してければGlobを使う
Clean('all', Glob('*.log'))


逆にクリーンアップ時に削除して欲しくないファイルなどは「NoClean」で指定する。
例えば「Install」したファイルも標準では削除対象になってしまうので、「NoClean」を使う。

a = Program('a.c')
a_inst = Install('/usr/bin', a)

NoClean(a_inst)


SCons入門(3) - Pashango’s Blog