http://nxsy.org/code/tgopenidlogin/からもってきたものをRPM化した。
いつものようにhttp://yum.tonic-water.com/collection/にあります。
2008年9月30日火曜日
2008年9月20日土曜日
2008年9月18日木曜日
爆撃
189.54.102.228 - - [15/Sep/2008:03:04:05 +0900] "GET /~andre/ HTTP/1.1" 403 328
189.54.102.228 - - [15/Sep/2008:03:04:06 +0900] "GET /~andrea/ HTTP/1.1" 403 330
189.54.102.228 - - [15/Sep/2008:03:04:07 +0900] "GET /~andreas/ HTTP/1.1" 403 332
あからさまにおかしなアクセスだ・・・。
辞書由来のユーザ名をなめようとするアクセスだ。
当然Blacklist行き。
2008年9月16日火曜日
python VM v.s. V8
どういうわけだか、v8は圧倒的に速いです。
おそらく、関数呼び出しをいじっているのでしょう。
test.py
test.js(test.pyより自動生成)
おそらく、関数呼び出しをいじっているのでしょう。
[nori@Asama]~/Desktop/work/packaging/v8/fromGoogle% time python test.py
102334155
python test.py 142.48s user 0.02s system 99% cpu 2:22.58 total
[nori@Asama]~/Desktop/work/packaging/v8/fromGoogle% time ./v8 test.js
102334155
./v8 test.js 6.87s user 0.00s system 99% cpu 6.879 total
test.py
def fib(n):
if n < 0:
return 0
elif n == 1:
return 1
return fib(n-1) + fib(n-2)
print fib(40)
test.js(test.pyより自動生成)
function len(s) {
return s.length;
}
function dict() {
var arr = new Array();
for (var i=0;iarr[dict.arguments[i]] = dict.arguments[i+1]
}
arr.toString = function() {
var result = "";
for (var key in arr)
{
if (result.length) result += ", "
result += String(key) + ": " + String(arr[key])
}
return "{" + result + "}";
}
return arr;
}
function fib(n) {
if (n < 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
}
return fib(n - 1) + fib(n - 2);
}
print( String(fib(40)), ' ', "\n");
2008年9月15日月曜日
pngを吐くbrowserとかないの?
pngを吐くbrowserとかないのかね。
javascriptを実行できてcuiなbrowser。pythonからdriveできればいい。
とかできたらうれしい。もちろんdynamicなものがあるのでそれは問題だが。
- 時間でeventがfireして動作
- mouse hover
- on focus
etc...
wに対してイベントを送ることができれば・・・ってwってbrowser coreじゃん。
javascriptを実行できてcuiなbrowser。pythonからdriveできればいい。
import webbrowesermodule
w = webbrowesermodule.new()
w.setlocation('http://www.asahi.com')
im = w.capture()
im.show() #xvで表示
とかできたらうれしい。もちろんdynamicなものがあるのでそれは問題だが。
- 時間でeventがfireして動作
- mouse hover
- on focus
etc...
wに対してイベントを送ることができれば・・・ってwってbrowser coreじゃん。
標準入出力でいいや・・・。
g++ -Iinclude hello_world.cpp -o hello_world libv8.a -lpthread -m32
とかしてあげないと駄目なのです。
さて、標準入力からscriptを取るように書き換えるか。
あ、sample下のshell.ccでいいのか。
しかしdocumentへのアクセスは当然できない。ので、py2jsを噛ましたときにdocument.writeに書き換わるprintを使えない。
printの実装を書き換えて、document.writeしないで、print(...)するようにすべきだな。shell.ccではprint関数が定義されているようなので。
v8を使いこなしてもdomをpy2jsの中で使えるようにするのには関係ないwww. v8はdomなしでしょ。まあ、ほかの機能はtestできますな。
server sideでaspをするajajaなるものがあるらしい。
野菜ジュースの続き
cythonが馬鹿をやっているようだ。m32なv8をつかって、m64なext_buildをやろうとする。
Scons自体は歴史がだいぶ長い。copyrightを見てもわかるし、すでに2002には記事を書いている人がいた。
Scons自体は歴史がだいぶ長い。copyrightを見てもわかるし、すでに2002には記事を書いている人がいた。
Python On 野菜ジュースをつかったJavaScript On Python

PythonのコードをJavaScriptにコンバートするpy2jsを読んで、コードを持ってきて俺スタイルに書き直す。
cuiでテストできんな・・・と思っていたところ、V8 on pythonなるものがあることを発見。LL futureで古い言語、新しい言語ででてきたLLVMの話が思い出される。あれはTamarinだったっけ?
ま、いいや。
sconsはyumでdriesから入れることができる。
Cythonをパッケージ・・・がv8のshared libraryがbuildできない。
/usr/bin/ld: warning: i386 architecture of input file
`obj/release/snapshot-empty.os' is incompatible with i386:x86-64 output
こんな感じ
arser.cc:(.text+0xa932): undefined reference to `operator new(unsigned int)'
obj/release/platform-linux.os: In function `v8::internal::OS::CreateSemaphore(int)':
platform-linux.cc:(.text+0x31f): undefined reference to `operator new(unsigned int)'
とかなる。ん~~ということはg++のoptionがおかしいのだろうか。
どういう風にoptionが渡されるかSconsをチェック。makeをreplaceするためのツールらしい。pythonでできているようだ。そういえばpython自体はいまはどうなっているんだ?Sconsにかわったのかな?
g++ --target-helpでわかった。
Target specific options:
-m128bit-long-double sizeof(long double) is 16
-m32 Generate 32bit i386 code
-m3dnow Support 3DNow! built-in functions
-m64 Generate 64bit x86-64 code
-m32でbuildされてる。だめじゃこりゃ。
LIBRARY_FLAGS = {
'all': {
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING']
},
'gcc': {
'all': {
'DIALECTFLAGS': ['-ansi'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS',
'-fno-strict-aliasing'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'],
'LIBS': ['pthread']
},
'mode:debug': {
'CCFLAGS': ['-g', '-O0'],
'CPPDEFINES': ['ENABLE_DISASSEMBLER', 'DEBUG']
},
'mode:release': {
'CCFLAGS': ['-O2']
},
'wordsize:64': {
'CCFLAGS': ['-m32'],
'LINKFLAGS': ['-m32']
}
},
Scriptをs/m32/m64/gとかしてscons library=shared wordsize=64とするも、
LOGGING_AND_PROFILING src/accessors.cc
src/checks.h: In function 'void CheckEqualsHelper(const char*, int, const char*, void*, const char*, void*)':
src/checks.h:139: error: cast from 'void*' to 'int' loses precision
src/checks.h:139: error: cast from 'void*' to 'int' loses precision
ぼーん。void*が64bitなのにintが32bitでうまくいかない。
ああ、ライブラリ自体が実行時にassembly codeを生成するから、32bit強制だったかな?
-cしてもobj下が消えないし。使い勝手が違うのに慣れるまでアレだね。
linker側の設定をいじるか、これは。
/
g++ -o obj/release/snapshot-empty.os -c -ansi -pedantic -Wall -Werror -W
-Wno-unused-parameter -fno-strict-aliasing -O2 -m32 -fPIC -DENABLE_LOGGING_AND_PROFILING
src/snapshot-empty.cc
あ、-m32がない!だめぽ。Scons Scriptの直し方わからないので、g++ -m32 (ryを実行
[nori@Asama]~/Desktop/work/packaging/v8/fromBitbucket/v8onpython% python setup.py build_ext --inplace
running build_ext
building 'v8onpython' extension
gcc -pthread -shared build/temp.linux-x86_64-2.4/v8onpython.o -Lv8-src -lv8 -o v8onpython.so -m32
/usr/bin/ld: warning: i386:x86-64 architecture of input file `build/temp.linux-x86_64-2.4/v8onpython.o' is incompatible with i386 output
build/temp.linux-x86_64-2.4/v8onpython.o: In function `__Pyx_AddTraceback':
/home/nori/Desktop/work/packaging/v8/fromBitbucket/v8onpython/v8onpython.cpp:780: undefined reference to `PyString_FromString'
つーか、これからしておかしい。
creating build/temp.linux-x86_64-2.4
gcc -pthread -fno-strict-aliasing -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fPIC -Iv8-src/include -I/usr/include/python2.4 -c v8onpython.c -o build/temp.linux-x86_64-2.4/v8onpython.o -m32
setup.pyから32bitを強制する方法は?
extra_compile_args=["-m32"],
extra_link_args=["-m32"],
コレ以外には?最終的なpackageのarchを32にしたいんだよね、x86-64じゃなくて。
2008年9月13日土曜日
ETag, if-match, etc
ETagをチェックしてpageの生成をせずに304を返せるdecoratorを実装した。これでかなりガシガシcacheされるはず。
- Revistion番号をETagとして付加する
- requestのif-none-matchをチェックしてETagがマッチするならそもそもにresponseを生成しない。
ちょっと特殊。コードのバージョンが同じなら同じimageを吐くので。
普通は動的にpageを生成してからmd5を計算してmatchしたら304する。
wikiのpageとかにも応用できるはず。pageにversionを振っておいて、そのversionをETagに突っ込む。
実装に当たってはcherrypyのコードを参考にした。
- Revistion番号をETagとして付加する
- requestのif-none-matchをチェックしてETagがマッチするならそもそもにresponseを生成しない。
ちょっと特殊。コードのバージョンが同じなら同じimageを吐くので。
普通は動的にpageを生成してからmd5を計算してmatchしたら304する。
wikiのpageとかにも応用できるはず。pageにversionを振っておいて、そのversionをETagに突っ込む。
実装に当たってはcherrypyのコードを参考にした。
2008年9月12日金曜日
裏番組
あーゆー雰囲気はなんかはかどるんですよね~~。
裏番組
cherrypyを読む
body = cherrypy.response.body[0]
の謎を解こう。
from threading import local
で、
request = _ThreadLocalProxy('request')
・・・
def __getattr__(self, name):
childobject = getattr(serving, self.__attrname__)
return getattr(childobject, name)
アクセスはすべてリダイレクト。
じゃあ、いつthreadが作られて、dispatchされるのか?
_cpwsgiserver.py
にある。
class CherryPyWSGIServer(object):
と
class WorkerThread(threading.Thread):
で、これらが
RequestHandlerClass = HTTPRequest
がQueueに積まれたときに処理を行う。
WorkerThreadのなかで
response = request.wsgi_app(request.environ,
request.start_response)
としているところで、userが書いたappが実行される。
self.mount_points = wsgi_app
はなんなのか?
wsgiの仕様 ( ja ) をよめばいいのかな?
裏番組
cherrypyを読む
body = cherrypy.response.body[0]
の謎を解こう。
from threading import local
で、
request = _ThreadLocalProxy('request')
・・・
def __getattr__(self, name):
childobject = getattr(serving, self.__attrname__)
return getattr(childobject, name)
アクセスはすべてリダイレクト。
じゃあ、いつthreadが作られて、dispatchされるのか?
_cpwsgiserver.py
にある。
class CherryPyWSGIServer(object):
と
class WorkerThread(threading.Thread):
で、これらが
RequestHandlerClass = HTTPRequest
がQueueに積まれたときに処理を行う。
WorkerThreadのなかで
response = request.wsgi_app(request.environ,
request.start_response)
としているところで、userが書いたappが実行される。
self.mount_points = wsgi_app
はなんなのか?
wsgiの仕様 ( ja ) をよめばいいのかな?
RCP 4th memo
ひそかにcherrypy/TGを一人で読んでました(裏番組)
質疑応答では一応突っ込みを入れましたが・・・。
RCP 4th, string.Templateにみるmetaclass
発表者:伊藤俊輔
3.0でString moduleの廃止が検討されたが、Templateがあるのでやめになった。3.0でもっと強力になるらしい(ats)
予習内容:
最終的には%に落ちる。
string.pyがimport された時点で_TemplateMetaclassのpatternがcompileされる。
_TemplateMetaclass::__init__の引数のdctはclass Templateのクラス変数。
30分近く待つ
プロジェクタの準備が整わない・・・
ざらっとみまわすとMac派が多い。
- 用途と使い方
- メソッド
- メタクラス
文字列の雛形を用意しておいて、後から値を当てはめる
データ出力時によく使われる。
%演算
プレースホルダ %s etc
複数あるときはtupleを与える。
複数与えるときは、順番だけだとつらい。
%(name)というものがある。 %(\([a-zA-Z]+\))?[sf...])
その場合はtupleではなくdictであたえる。
%がほしいときは%%としてエスケープ
キーが無いときはKeyError
発表者かなり上がり気味。
メソッド
substitute(dict..)
substitute(**kw)
実装:re.subでの置換
使わなかったプレースホルダはそのまま残る。
プレースホルダ名はpython識別子のみ。i.e. 数字のみはダメ
$は$でエスケープ
ふとおもったのだが、
"""A string class for supporting $-substitutions."""
__metaclass__ = _TemplateMetaclass
delimiter = '$'
idpattern = r'[_a-z][_a-z0-9]*'
これの順番って変えても動くの?
いんべいるど~~~~って何?
インバリッドのこと?
lines = self.template[:i].splitlines(True)
スタートするところまで取り出す。
あーぎす?
アーギュメンツのこと?
メタクラスを使う必然性は?
google code searchしたか?
テンプレートにunicodeが含まれているとなにがおこるか?(re.Uしてない)
キーにunicodeは許されないだろうからOK?
callable
module ns
func ns
func ns
module ns
class ns
class ns
名前空間の解決:近くのものから取ってくる。
動的スコープ、静的スコープ
patternの書き換えには限度がある。
どう書き換えたいのか???
何か仕様で押し付けられたとき?!
哲学・・・入ってきた?
質疑応答では一応突っ込みを入れましたが・・・。
RCP 4th, string.Templateにみるmetaclass
発表者:伊藤俊輔
3.0でString moduleの廃止が検討されたが、Templateがあるのでやめになった。3.0でもっと強力になるらしい(ats)
予習内容:
最終的には%に落ちる。
string.pyがimport された時点で_TemplateMetaclassのpatternがcompileされる。
_TemplateMetaclass::__init__の引数のdctはclass Templateのクラス変数。
30分近く待つ
プロジェクタの準備が整わない・・・
ざらっとみまわすとMac派が多い。
- 用途と使い方
- メソッド
- メタクラス
文字列の雛形を用意しておいて、後から値を当てはめる
データ出力時によく使われる。
%演算
プレースホルダ %s etc
複数あるときはtupleを与える。
複数与えるときは、順番だけだとつらい。
%(name)というものがある。 %(\([a-zA-Z]+\))?[sf...])
その場合はtupleではなくdictであたえる。
%がほしいときは%%としてエスケープ
キーが無いときはKeyError
発表者かなり上がり気味。
メソッド
substitute(dict..)
substitute(**kw)
実装:re.subでの置換
使わなかったプレースホルダはそのまま残る。
プレースホルダ名はpython識別子のみ。i.e. 数字のみはダメ
$は$でエスケープ
ふとおもったのだが、
"""A string class for supporting $-substitutions."""
__metaclass__ = _TemplateMetaclass
delimiter = '$'
idpattern = r'[_a-z][_a-z0-9]*'
これの順番って変えても動くの?
いんべいるど~~~~って何?
インバリッドのこと?
lines = self.template[:i].splitlines(True)
スタートするところまで取り出す。
あーぎす?
アーギュメンツのこと?
メタクラスを使う必然性は?
google code searchしたか?
テンプレートにunicodeが含まれているとなにがおこるか?(re.Uしてない)
キーにunicodeは許されないだろうからOK?
callable
module ns
func ns
func ns
module ns
class ns
class ns
名前空間の解決:近くのものから取ってくる。
動的スコープ、静的スコープ
patternの書き換えには限度がある。
どう書き換えたいのか???
何か仕様で押し付けられたとき?!
哲学・・・入ってきた?
multiprocessing
http://docs.python.org/dev/library/multiprocessing.html#module-multiprocessing
なんかもとめていたものかもしれん。要チェックだ
なんかもとめていたものかもしれん。要チェックだ
成果ブツ
まずは第一弾ということで。

"http://www.backgammonbase.com/
topただの普通のhtmlです。
ただ、すべての画像は動的に生成しています。
(Pageを開いたときにserver側で作り出してます)
http://image.backgammonbase.com/form
ではposition idとmatch idをgnubgからcopyしてformに貼り付けると局面を生成できます。
http://www.backgammonbase.com/MySystem.txt
資料の原稿(書きかけ)。これをいままでに作ったプログラムをつかって
htmlに加工します。でできたのが
http://www.backgammonbase.com/MySystem.html
これは最近書き始めた入門用の資料
"http://www.backgammonbase.com/
topただの普通のhtmlです。
ただ、すべての画像は動的に生成しています。
(Pageを開いたときにserver側で作り出してます)
http://image.backgammonbase.com/form
ではposition idとmatch idをgnubgからcopyしてformに貼り付けると局面を生成できます。
http://www.backgammonbase.com/MySystem.txt
資料の原稿(書きかけ)。これをいままでに作ったプログラムをつかって
htmlに加工します。でできたのが
http://www.backgammonbase.com/MySystem.html
これは最近書き始めた入門用の資料
2008年9月11日木曜日
reverse proxy便利すぎ
「間接化するためにLayerを挟むことが解決策だ」とはよく言ったものだ。reverse proxyでマップすればなんとかなるものだ。もちろん、破綻しないように注意は必要だ。まあ、proxyされるサーバのつくりをシンプルに保つのが肝だろう。
しかしvhost + reverse proxyって、病的な気がするなぁ。
しかしvhost + reverse proxyって、病的な気がするなぁ。
yumお亡くなり
makecacheしたらおかしくなった。
(process:13010): GLib-WARNING **: GError set over the top of a previous GError or uninitialized memory.
This indicates a bug in someone's code. You must ensure an error is NULL before it's set.
The overwriting error message was: Parsing other.xml error: Entity 'gt' not defined
Traceback (most recent call last):
File "/usr/bin/yum", line 29, in ?
yummain.main(sys.argv[1:])
File "/usr/share/yum-cli/yummain.py", line 105, in main
result, resultmsgs = base.doCommands()
File "/usr/share/yum-cli/cli.py", line 293, in doCommands
return self.yum_cli_commands[self.basecmd].doCommand(self, self.basecmd, self.extcmds)
File "/usr/share/yum-cli/yumcommands.py", line 317, in doCommand
base.repos.populateSack(mdtype='otherdata', cacheonly=1)
File "/usr/lib/python2.4/site-packages/yum/repos.py", line 242, in populateSack
sack.populate(repo, mdtype, callback, cacheonly)
File "/usr/lib/python2.4/site-packages/yum/yumRepo.py", line 168, in populate
dobj = repo_cache_function(xml, csum)
File "/usr/lib64/python2.4/site-packages/sqlitecachec.py", line 57, in getOtherdata
self.repoid))
TypeError: Parsing other.xml error: Detected an entity reference loop
2008年9月10日水曜日
forkしすぎ?
Traceback (most recent call last):
File "bglib/doc/bgwiki.py", line 553, in ?
fuzz_it(wGene, Formatter(db))
File "/home/nori/Desktop/work/bglib/src/bglib/doc/fuzzing.py", line 94, in fuzz_it
pid = os.fork()
OSError: [Errno 11] Resource temporarily unavailable
ん~。
processの使い捨ては問題があるようだ。
fork version
import select
import time
import os
r, w = os.pipe()
pid = os.fork()
if pid:
i, o, e =select.select([r],[], [], 3)
assert not o
assert not e
if i:
print 'done! with ', os.read(r, 1000)
else:
print 'time out'
else:
time.sleep(2)
os.write(w, '1000')
code snipet for child process with timeout.
子プロセス。loop.py
親プロセス。selectで3秒まつ。何も書き出されなかったらtimeout。
書き出されたらそれをprintして終了。
import time
import sys
time.sleep(2)
print 1000
親プロセス。selectで3秒まつ。何も書き出されなかったらtimeout。
書き出されたらそれをprintして終了。
import select
import subprocess
p = subprocess.Popen(['/usr/bin/python','./loop.py'], stdout=subprocess.PIPE)
i, o, e =select.select([p.stdout],[], [], 3)
assert not o
assert not e
if i:
print 'done! with ', i[0].read()
else:
print 'time out'
2008年9月3日水曜日
名前つき正規表現と繰り返し
正規表現で(?P)*みたいなことをしてgroupdictで取り出すと、最後のidしか取り出せない。
groupsだとidでアクセスできない。 matchobj.group('id')はgroupdictを同じ結果。
groupdictのitemがmatchじゃなくてmatchのsequenceを保持していてほしいのですが・・・。
このままだと*を含むやつで切り出してからもう一回マッチをかけないといけない。ダサっ!
groupsだとidでアクセスできない。 matchobj.group('id')はgroupdictを同じ結果。
groupdictのitemがmatchじゃなくてmatchのsequenceを保持していてほしいのですが・・・。
このままだと*を含むやつで切り出してからもう一回マッチをかけないといけない。ダサっ!
2008年9月1日月曜日
metaclass
まずは書いてみる。
これを実行すると
と表示される。MyClassのinstanceは生成していないのでMyClass::__init__は表示されない。
MyClass自体は生成され、その過程で前出の表示が行われる。このfileをimportしても表示される。(ファイルを読んで評価したタイミングというべきかな?)
で、前のentryのTemplateがmetaclassでは、正規表現のcompileが行われているので、
としているようなファイルをimportするのと同じタイミングで正規表現がCompileされる。dctの中身にpatternがあるかどうかチェックしているので一回しかcompileされない。この点に関しては同じ事はinstance/classレベルでも可能。
class _MyMetaclass(type):
def __init__(cls, name, bases, dct):
print '_MyMetaclass::__init__'
class MyClass(object):
__metaclass__ = _MyMetaclass
def __init__(self):
print 'MyClass::__init__'
これを実行すると
'_MyMetaclass::__init__
と表示される。MyClassのinstanceは生成していないのでMyClass::__init__は表示されない。
MyClass自体は生成され、その過程で前出の表示が行われる。このfileをimportしても表示される。(ファイルを読んで評価したタイミングというべきかな?)
で、前のentryのTemplateがmetaclassでは、正規表現のcompileが行われているので、
xxx = re.compile(yyy)
としているようなファイルをimportするのと同じタイミングで正規表現がCompileされる。dctの中身にpatternがあるかどうかチェックしているので一回しかcompileされない。この点に関しては同じ事はinstance/classレベルでも可能。
%での置換
Python Code Reading 04で、metaclassをやるらしい。題材はstring.Template。
気になってすこしstring.Templateのコードを読んでみた。シンプルなクラスで勉強の題材として適切だ。
で、気づいたのは%で辞書を渡してもOK。うっかり。
2.3.6.2 文字列フォーマット操作
%がかなり高機能であることがわかる。%とstring.Templateの機能の差はそれほど大きく感じない。
metaclassをつかっている理由は、cls.patternを動的に生成したいからなのだが、instanceではいけない理由はどこにあるのだろうか?この点はclass設計上、大事なポイントな気がする。
metaclass内でTemplate文法を決めている箇所があるが、これはgpatternとか名づけてTemplateのclass変数として持てない理由はどこにあるのでしょうか?
しかも使う側はself.patternという形で触っていてcls.patternとしては触っていない。
気になってすこしstring.Templateのコードを読んでみた。シンプルなクラスで勉強の題材として適切だ。
で、気づいたのは%で辞書を渡してもOK。うっかり。
pattern = _TemplateMetaclass.pattern % {
'delim' : _re.escape(cls.delimiter),
'id' : cls.idpattern,
}
2.3.6.2 文字列フォーマット操作
%がかなり高機能であることがわかる。%とstring.Templateの機能の差はそれほど大きく感じない。
metaclassをつかっている理由は、cls.patternを動的に生成したいからなのだが、instanceではいけない理由はどこにあるのだろうか?この点はclass設計上、大事なポイントな気がする。
metaclass内でTemplate文法を決めている箇所があるが、これはgpatternとか名づけてTemplateのclass変数として持てない理由はどこにあるのでしょうか?
pattern = r"""
%(delim)s(?:
(?P%(delim)s) | # Escape sequence of two delimiters
(?P%(id)s) | # delimiter and a Python identifier
{(?P%(id)s)} | # delimiter and a braced identifier
(?P) # Other ill-formed delimiter exprs
)
しかも使う側はself.patternという形で触っていてcls.patternとしては触っていない。
def substitute(self, *args, **kws):
...
return self.pattern.sub(convert, self.template)
登録:
投稿 (Atom)