2009年2月27日金曜日

Acquisition cont'ed

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
/opt/Plone-2.5.3/lib/python/Acquisitionに.soがあった。
テストコードから明らか。朝、目覚めたときに脳裏に去来したコードに近い。googleでしらべたときにネット上に転がっている文章は、なんであんなに説明に迷走するのかわからない。こっから先は_Acquisition.cを見るか、ベースとなった.pyを探すかというところ。

>>> import ExtensionClass, Acquisition

>>> class C(ExtensionClass.Base):
... color='red'

>>> class A(Acquisition.Implicit):
... def report(self):
... print self.color

>>> a = A()
>>> c = C()
>>> c.a = a

>>> c.a.report()
red

>>> d = C()
>>> d.color = 'green'
>>> d.a = a

>>> d.a.report()
green

>>> a.report() # raises an attribute error
Traceback (most recent call last):
...
AttributeError: color


google codeの結果。Cの実装は非本質的なものがいっぱい入っていて密度が低いのでいやなんだよね。あとはtest codeがあるので、そのtestをpassするようなpyを実装して理解を確認するとかかな。

コンピュータの方向性:書き捨ての時代

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ディスク<帯域<CPUの順に制限がキツくなるGoogle App EngineのQuota構成から見るコストパフォーマンスの高いシステム構成

ここ数年を振り返ると,ディスク容量のチープ化が一番進んでいるんですね。帯域はインフラ整備が必要なのでそう簡単にはチープ化しないし,CPUの速度も実は以前ほど急速に向上していず,マルチコア化とか並列化で数字を稼いでいるというのが現状


並列処理で動画とかの再生が軽いとかだからなぁ~。周波数はだいぶ前からあがってない。学生のときに3GHzのマシンが作れる話を聞いて指導教官が電子レンジと同じだ~みたいなことを行っていた。プロセスの微細化と周波数の向上の為の電圧あげは消費電力の観点からろくなことが無い。消費電力=熱でもあるので、廃熱が間に合わない。これは今始まった話じゃなくて、かなり前からだ。ソフトウェアががんばらないとどうにもなら無い。コンパイラだか言語だかが何とかしないといけない。環境(仮想化)は、コンパクト化してくれるが、速くしてくれるわけじゃない。もっとも、人間の絡むプロセスという観点からは、仮想化はdeployのコストを下げるので間違いなくよいことなのだが。ただ、これは広い意味での性能向上であって、quotaをあげる理由にはならない。

コンパクト化は地球シミュレータも例外ではない。
「地球シミュレータ」:計算能力毎秒131兆回 機種更新

 旧機種はスパコン640台を接続していたが、性能向上により160台に減らした。計算能力は毎秒131兆回(理論値)と旧機種の3.2倍。消費電力は2~3割少なく、設置面積も半分の650平方メートルで済んだ。


自分自身もそうだし、周りの知人もそうだが、新しいマシンを買うと、前のマシンのデータがそっくりそのままコピーされている。oldとか名前がついてね。一言で言うと、ディスク容量を消費する速度よりも、ディスク容量増える速度のほうが圧倒的に速い。一番かさばる使い道は動画だろうが、それでも1Tを満タンにするのは大変だろう。満タンにできたところで、そのデータをすべて視聴できないだろう。具体的な例を挙げると、1分の間にYouTubeに到着する動画の再生時間は、1分を大幅に超えている(すべてに意味があるとはいわないが)。そうでなくても世界中のTV局が流すコンテンツすべてをあわせても視聴できないでしょう。すでに生産過剰で、かつそれを上回るdisk容量供給が存在する。

ITProのどの記事かは失念したが、メールを全部保存しているのは変、gmail容量でかすぎ、とか書いている人がいたが、ナンセンス。供給過剰の量が質を変えるのだ。diskがありあまることを前提でデザインをすべき。ましてやdisk容量の節約が必要になるような製品はすでに死んでいる。

大学院でDatabaseの授業を受けたときに印象に残っているのは、教授

  • 「TSUTAYAは君たちの性癖をしっている」、補足すると要はamazonのsuggestとかと同じ。

  • 「過去には写真一枚があればよく情報が残っている部類に入る世代があったが、そのうち生まれてから死ぬまでのデータをすべてデジタイズした世代が出てくる。容量的にはそれは可能で、indexingが問題だ。」


といったこと。

私の予想では、すべてにおいてデータを消さなくなる。gitとかsvnのrepositoryみたいにすべて変更履歴を保存するようになる。消す理由(ディスク領域の解放・回収)が無いから。名前のほうが足りないが、それは変更履歴の保存という形で回収できる。そして、disk/memoryを気にするスタイルからすべてのobjectをpersistentなものとして管理するスタイルに変わるだろう。なんせ安いので。そのpersistentな管理自体がrepositoryのようなversionを持った形式に近づくのではないだろうか。systemを任意の時点に巻き戻せるのだ。言い方を変えるとmutateするのではなくappendしかしない。

Zopeをゴリゴリ読んでいるのもpersistentなsystemの実装が見たいというのが理由だ。そのうちsmall talk系もやるだろう。Erlangとかも興味深い。いずれにせよ、過去の資産が使えないと人が移行してこないので、私が言語を作ることは無いだろう。

2009年2月26日木曜日

Acquisition

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
関係あるようだ。Five(移行用レイヤ、おそらく2+3だから)の中でこんなのがある。

src/Products/Five/bbb.py:22:class AcquisitionBBB(object):
src/Products/Five/bbb.py:23: """Emulate a class implementing Acquisition.interfaces.IAcquirer and
src/Products/Five/bbb.py:24: IAcquisitionWrapper.


Acquisition @ zope.org

The concept is simple: if a named object is not found as an attribute of the object you're searching, its containers are searched until the object is found. In this way, acquisition can add behavior to objects.


Re:Zopeはすばらしいですmojixってあのzopeジャンキー日記のmojixさんでしょうね。

Environment Acquisitionのページ
http://www.ccs.neu.edu/home/lorenz/research/acquisition/
には、誕生からZopeにいたる経緯が書いてあって、

1. コンセプトがOOPSLA '96で発表
2. 似たものをDavid AscherがPythonで実装
3. Jim FultonがPythonで実装(これがZopeに入る)

といった流れをたどったようです。

つまり環境獲得(Environment Acquisition)は、
もともと学術的な、OO好きの人にはたまらないようなところから出てきて、
それがPythonで実装されてZopeに入り、すごく実用的なものになった、という経緯なわけで、
興味深いと思います。

環境獲得について、David Asherは
「インスタンスが、継承(is-a)関係だけでなく、包含(has-a)関係によっても、親から属性を得られるようにする」
といった説明をしています。

これがZopeでは、上位ディレクトリで共通ヘッダやフッタなどを定義しておけば、その配下にあるすべてのディレクトリでそれを共有できる、といったかかたちで実現されているわけです。


mojixさんの/.Jの日記をさしていると思われる、誰かのメモのgoogleのキャッシュ


Environmental Acquisition

件の烈さんの資料より

トラバーサルは柔軟にオブジェクト間の関係を定義でき、
「獲得」と呼ばれるトリックも!

この説明では駄目すぎる。

練習問題としてよさそう。
[plone-users 1185] Zope 管理者と Plone 管理者の分離について


Zope活用例

これらの各エリアは、WebNationの場合と同様、それぞれ独立のZopeオブジェクトとして実装されていると思われます。「acquisition (獲得)」の仕組みにより、深い階層のページでも、最上位ディレクトリにある要素を自動的に継承して用いることができます。


オブジェクト・パブリッシング・システムなんです (スコア:2, 参考になる)

ディレクトリ階層のように見せているのは、実はZopeの名前空間でもあり、クラスや継承、逆継承(?)acquisitionなどをサポートしてます。


名前空間をmappingしているという観点ではapacheのLocationも同じだなぁ。

「逆継承」よりも、CSSで上位のelementのstyleが下位のelementに適用されるinheritanceのほうが近いだろう。element型としての継承関係に由来しているわけではないのだから。inheritするという性質は継承からきているかもしれないが、inheritされる値はacquisitionといったほうが近いだろう。

そういうわけで、__of__なのはしっくりきた。

zope DefaultPublishTraverse:publishTraverse

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
boboとは酔っ払ったという意味らしい。googleで調べてみるとtraverseをカスタマイズするための属性のようだ。千鳥足でtraverseするといったところか。




def publishTraverse(self, request, name):
object = self.context
URL=request['URL']

if name[:1]=='_':
raise Forbidden("Object name begins with an underscore at: %s" % URL)



こちらはdelegateされているので何でもあり。なぜ__bobo_traverse_を使っていて、カスタムトラバース用のInterfaceが存在していないのだろう?(しているのかもしれないが)

if hasattr(object,'__bobo_traverse__'):
try:
subobject=object.__bobo_traverse__(request, name)
if type(subobject) is type(()) and len(subobject) > 1:
# Add additional parents into the path
# XXX There are no tests for this:
request['PARENTS'][-1:] = list(subobject[:-1])
object, subobject = subobject[-2:]
except (AttributeError, KeyError, NotFound), e:
# Try to find a view
subobject = queryMultiAdapter((object, request), Interface, name)
if subobject is not None:
# OFS.Application.__bobo_traverse__ calls
# REQUEST.RESPONSE.notFoundError which sets the HTTP
# status code to 404
request.response.setStatus(200)
# We don't need to do the docstring security check
# for views, so lets skip it and return the object here.
if IAcquirer.providedBy(subobject):
subobject = subobject.__of__(object)
return subobject
# No view found. Reraise the error raised by __bobo_traverse__
raise e

普通のケース。aq_baseはApp/Common.pyの中にある。


def aq_base(ob, getattr=getattr):
# Return the aq_base of an object.
return getattr(ob, 'aq_base', ob)



else:
# No __bobo_traverse__
# Try with an unacquired attribute:
if hasattr(aq_base(object), name):
subobject = getattr(object, name)

aq_baseの意味するところがわからない。どういうプロトコルを構成しようとしているのだろうか?

else:
# We try to fall back to a view:
subobject = queryMultiAdapter((object, request), Interface,
name)
if subobject is not None:
if IAcquirer.providedBy(subobject):
subobject = subobject.__of__(object)
return subobject

# And lastly, of there is no view, try acquired attributes, but
# only if there is no __bobo_traverse__:
try:
subobject=getattr(object, name)
# Again, clear any error status created by __bobo_traverse__
# because we actually found something:
request.response.setStatus(200)
return subobject
except AttributeError:
pass

# Lastly we try with key access:
try:
subobject = object[name]
except TypeError: # unsubscriptable
raise KeyError(name)




コメントがすべて。問題はなぜそういうポリシーを採用しているかだ。次のコメントを読むと、2.2.2でmutableなやつのdocstringがどうのこうのと書いてある。おそらくは、adapter経由で意図していない公開が起こらない安全側に倒したのだろう。組み込み型はfile終わりのほうで列挙されている。

# Ensure that the object has a docstring, or that the parent
# object has a pseudo-docstring for the object. Objects that
# have an empty or missing docstring are not published.
doc = getattr(subobject, '__doc__', None)
if doc is None:
doc = getattr(object, '%s__doc__' % name, None)
if not doc:
raise Forbidden(
"The object at %s has an empty or missing " \
"docstring. Objects must have a docstring to be " \
"published." % URL
)




# Hack for security: in Python 2.2.2, most built-in types
# gained docstrings that they didn't have before. That caused
# certain mutable types (dicts, lists) to become publishable
# when they shouldn't be. The following check makes sure that
# the right thing happens in both 2.2.2+ and earlier versions.

if not typeCheck(subobject):
raise Forbidden(
"The object at %s is not publishable." % URL
)

return subobject

zope:traverseName

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ここは組み込み型objectの上書きじゃなくてobだ。:D
name spaceってZopeのobjectの空間のname spaceをurlで表記できるということ?



def traverseName(self, ob, name):
if name and name[:1] in '@+':
# Process URI segment parameters.
ns, nm = nsParse(name)
if ns:
try:
ob2 = namespaceLookup(ns, nm, ob, self)
except TraversalError:
raise KeyError(ob, name)


__of__とAcquireは何か関係があるらしい。

if IAcquirer.providedBy(ob2):
ob2 = ob2.__of__(ob)
return ob2


ifの順番を最初のやつと入れ替えてelifで書けとか思うのは気のせい?name == '.'のケースにsliceしたobjectを生成しないので気持ちいい。速いとはいわない。

if name == '.':
return ob


これがおそらく一番普通のケース。

if IPublishTraverse.providedBy(ob):
ob2 = ob.publishTraverse(self, name)

obがdumbだとadapterを探す。

else:
adapter = queryMultiAdapter((ob, self), IPublishTraverse)
if adapter is None:
## Zope2 doesn't set up its own adapters in a lot of cases
## so we will just use a default adapter.
adapter = DefaultPublishTraverse(ob, self)

ob2 = adapter.publishTraverse(self, name)

return ob2

次の読み候補

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

  • IBrowserPublisher.providedBy

  • queryMultiAdapter

  • getRoles

  • traverseName

zope:traverse

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Zopeを理解しようということで、コード読みです。
プログラマでなくてもわかるZope 3紹介をみてオブジェクトパブリッシャがキモのようなので、それっぽいところを拾ってきて読むことにした。

読みの対象したブツ

commit e0cf424a7dcf28d776da2a7765884bc9f97e6755
Author: hannosch
Date: Mon Feb 23 12:49:08 2009 +0000

OFS.ObjectManager now fully implements the zope.container.IContainer interface and no longer just claims to do so. See the changelo


git-svn-id: svn://svn.zope.org/repos/main/Zope/trunk@97155 62d5b8a3-27da-0310-9561-8e5933582275

「class DefaultPublishTravers」でgoogle code検索すれば大体同じようなところにたどり着きます。


src/ZPublisher/BaseRequest.py class BaseRequestのメソッドtraverseである。



まずは準備。


def traverse(self, path, response=None, validated_hook=None):
"""Traverse the object space

The REQUEST must already have a PARENTS item with at least one
object in it. This is typically the root object.
"""
request=self
request_get=request.get
if response is None: response=self.response

# remember path for later use
browser_path = path



pathの正規化。あまりよくない。

  • /path/to/this → path/to/this

  • path/to/this/ → path/to/this

  • path/./to/./this → [path, to, this]

  • path/../path/to/this → [path, to, this]


をやっている。cleanという名前もどうかと思うし、この部分だけmake_path_listとか関数にすりゃいい。長くてかなわない。pathという名前がさしているものがstrからlistに変わっていて気持ち悪い。


# Cleanup the path list
if path[:1]=='/': path=path[1:]
if path[-1:]=='/': path=path[:-1]
clean=[]
for item in path.split('/'):
# Make sure that certain things that dont make sense
# cannot be traversed.
if item in ('REQUEST', 'aq_self', 'aq_base'):
return response.notFoundError(path)
if not item or item=='.':
continue
elif item == '..':
del clean[-1]
else: clean.append(item)
path=clean



acquireはなんでしょ。裏が取れてませんが、WebDAVのLockでしょう。

# How did this request come in? (HTTP GET, PUT, POST, etc.)
method=req_method=request_get('REQUEST_METHOD', 'GET').upper()

if method=='GET' or method=='POST' and not isinstance(response,
xmlrpc.Response):
# Probably a browser
no_acquire_flag=0
# index_html is still the default method, only any object can
# override it by implementing its own __browser_default__ method
method = 'index_html'
elif self.maybe_webdav_client:
# Probably a WebDAV client.
no_acquire_flag=1
else:
no_acquire_flag=0



request=selfとrequest_get=request.getなのだ。requestはdictっぽいなにか。HTTP Requestの各headerが収まっていると見ていいでしょう。組み込みのobjectがここで隠されるので注意(ぶー)。

URL=request['URL']
parents=request['PARENTS']
object=parents[-1]
del parents[:]



__bobo_があると挙動が変わるらしい。boboってなんの略だ?

self.roles = getRoles(None, None, object, UNSPECIFIED_ROLES)

# if the top object has a __bobo_traverse__ method, then use it
# to possibly traverse to an alternate top-level object.
if hasattr(object,'__bobo_traverse__'):
try:
object=object.__bobo_traverse__(request)
self.roles = getRoles(None, None, object, UNSPECIFIED_ROLES)
except: pass



pathとmethodのどちらも存在しないとこtは、応答するリソース存在しないこと。

if not path and not method:
return response.forbiddenError(self['URL'])



__of__を持っていると特別扱い。

# Traverse the URL to find the object:
if hasattr(object, '__of__'):
# Try to bind the top-level object to the request
# This is how you get 'self.REQUEST'
object=object.__of__(RequestContainer(REQUEST=request))
parents.append(object)



資料によればobjectはtreeをなしているらしく、そのルートからたどる時のスタックをpathから作る、最後のフェーズ。reverse()をしているのは.pop()を使って後ろからとりだすため。pathを抽象化する何かを作って、コンストラクタにurlを渡すとかではなく、べたべたに書いている。

steps=self.steps
self._steps = _steps = map(quote, steps)
path.reverse()

request['TraversalRequestNameStack'] = request.path = path
request['ACTUAL_URL'] = request['URL'] + quote(browser_path)


こいつは、とりあえずは、無視していい。

# Set the posttraverse for duration of the traversal here
self._post_traverse = post_traverse = []



かなり長いtry/finally, finallyはここ
rootからたどってname(str)のlist(path)からobjectのlist(parents)を作る。
try/finallyすることで途中でたどれなくても、できたところまでのobjectを返す。

entry_name = ''
try:
# We build parents in the wrong order, so we
# need to make sure we reverse it when we're done.


path(nameのlist)に関してのループ。一見してなんのループかわからない。

while 1:
bpth = getattr(object, '__before_publishing_traverse__', None)
if bpth is not None:
bpth(object, self)

path = request.path = request['TraversalRequestNameStack']
# Check for method:
if path:
entry_name = path.pop()
else:
# If we have reached the end of the path, we look to see
# if we can find IBrowserPublisher.browserDefault. If so,
# we call it to let the object tell us how to publish it.
# BrowserDefault returns the object to be published
# (usually self) and a sequence of names to traverse to
# find the method to be published.

# This is webdav support. The last object in the path
# should not be acquired. Instead, a NullResource should
# be given if it doesn't exist:
if (no_acquire_flag and
hasattr(object, 'aq_base') and
not hasattr(object,'__bobo_traverse__')):
if object.aq_parent is not object.aq_inner.aq_parent:
from webdav.NullResource import NullResource
object = NullResource(parents[-2], object.getId(),
self).__of__(parents[-2])



特定の(この場合はIBrowserPublisher)の指定する能力を持つobjectかどうかを判定している。無い場合は、アダプタを探し回る。

if IBrowserPublisher.providedBy(object):
adapter = object
else:
adapter = queryMultiAdapter((object, self),
IBrowserPublisher)
if adapter is None:
# Zope2 doesn't set up its own adapters in a lot
# of cases so we will just use a default adapter.
adapter = DefaultPublishTraverse(object, self)


再び名前objectを上書き。詳細はわからないが、treeのnodeをdownしているのは間違いないだろう。default_pathはadapter.browserDefaultしだい。

object, default_path = adapter.browserDefault(self)
if default_path:
request._hacked_path=1
if len(default_path) > 1:
path = list(default_path)
method = path.pop()
request['TraversalRequestNameStack'] = path
continue
else:
entry_name = default_path[0]

/で終わる名前の場合。HTTP METHODでかつそのMETHOD名に相当するmethod(python objectの)がある場合、methodはindex_htmlが使われる。このへんはIBrowserPublisherを見ればわかるはず。

elif (method and hasattr(object,method)
and entry_name != method
and getattr(object, method) is not None):
request._hacked_path=1
entry_name = method
method = 'index_html'

適切な表現とはいいがたいが、cgiっぽい挙動をする。objectが__call__を持っているとそいつを呼ぶのだろう。返す結果が実行結果かどうかはちょっとわからない。動的に生成されたobjectではなく、methodからroleを決定している。

else:
if hasattr(object, '__call__'):
self.roles = getRoles(object, '__call__', object.__call__,
self.roles)
if request._hacked_path:
i=URL.rfind('/')
if i > 0: response.setBase(URL[:i])
break

下に行く。どのobjectのどのattributeを見るかはurlから直接決まるのではなく、entry_nameで決まる。stepはそれのquoteしたもので、それから実際に返事をしたobjectのURLを作る。

step = quote(entry_name)
_steps.append(step)
request['URL'] = URL = '%s/%s' % (request['URL'], step)

try:
subobject = self.traverseName(object, entry_name)
if (hasattr(object,'__bobo_traverse__') or
hasattr(object, entry_name)):
check_name = entry_name
else:
check_name = None

self.roles = getRoles(
object, check_name, subobject,
self.roles)
object = subobject

例外から推定するに辞書だった場合は、__getitem__して、そうじゃない場合は__dict__を見るようだ。

except (KeyError, AttributeError):
if response.debug_mode:
return response.debugError(
"Cannot locate object at: %s" % URL)
else:
return response.notFoundError(URL)
except Forbidden, e:
if self.response.debug_mode:
return response.debugError(e.args)
else:
return response.forbiddenError(entry_name)



チェックしたものをappendする。

parents.append(object)

steps.append(entry_name)

parentsはreverseするのにstepsはしない。何故?
        finally:
parents.reverse()


とりあえず無視。

# Note - no_acquire_flag is necessary to support
# things like DAV. We have to make sure
# that the target object is not acquired
# if the request_method is other than GET
# or POST. Otherwise, you could never use
# PUT to add a new object named 'test' if
# an object 'test' existed above it in the
# heirarchy -- you'd always get the
# existing object :(
if (no_acquire_flag and
hasattr(parents[1], 'aq_base') and
not hasattr(parents[1],'__bobo_traverse__')):
if not (hasattr(parents[1].aq_base, entry_name) or
parents[1].aq_base.has_key(entry_name)):
raise AttributeError, entry_name

# After traversal post traversal hooks aren't available anymore
del self._post_traverse


reverseしたあとなので、一番最後に見つかったやつが[0]にいる。びみょー。

request['PUBLISHED'] = parents.pop(0)




# Do authorization checks
user=groups=None
i=0

if 1: # Always perform authentication.


どのobjectの__allow_groups__をgroupsとして使うかを決める。
parerntsはleafからrootに向かって配列されているので、自分で決められないと親にとあわせが行く。以下、再帰的に。これも_get_groupsとかでまとめて書いてほしい・・・。

last_parent_index=len(parents)
if hasattr(object, '__allow_groups__'):
groups=object.__allow_groups__
inext=0
else:
inext=None
for i in range(last_parent_index):
if hasattr(parents[i],'__allow_groups__'):
groups=parents[i].__allow_groups__
inext=i+1
break


groupsを使って仕事をする。

if inext is not None:
i=inext


old_validationは関数。default_validationじゃなくて、old_validationなのは、おそらく歴史的理由なのだろう。


def old_validation(groups, request, auth,
roles=UNSPECIFIED_ROLES):



if hasattr(groups, 'validate'): v=groups.validate
else: v=old_validation

auth=request._auth


認証に使う関数を探す。

if v is old_validation and self.roles is UNSPECIFIED_ROLES:
# No roles, so if we have a named group, get roles from
# group keys
if hasattr(groups,'keys'): self.roles=groups.keys()
else:
try: groups=groups()
except: pass
try: self.roles=groups.keys()
except: pass

if groups is None:
# Public group, hack structures to get it to validate
self.roles=None
auth=''


認証を実行。

if v is old_validation:
user=old_validation(groups, request, auth, self.roles)

ちょっと意味不明。vの引数が違うのか??

elif self.roles is UNSPECIFIED_ROLES: user=v(request, auth)
else: user=v(request, auth, self.roles)


認証の結果userが決まらなかったときに、path上のすべてのobjectについて、leafからrootに向かって、認証をこころみる。

while user is None and i < last_parent_index:
parent=parents[i]
i=i+1
if hasattr(parent, '__allow_groups__'):
groups=parent.__allow_groups__
else: continue
if hasattr(groups,'validate'): v=groups.validate
else: v=old_validation
if v is old_validation:
user=old_validation(groups, request, auth, self.roles)
elif self.roles is UNSPECIFIED_ROLES: user=v(request, auth)
else: user=v(request, auth, self.roles)


userがNoneでかつ、何らかの認証が要求されていたら、それは認証失敗。

if user is None and self.roles != UNSPECIFIED_ROLES:
response.unauthorized()


認証が成功していたら、それにまつわるフックがあれば実行して、認証の情報をセット。

if user is not None:
if validated_hook is not None: validated_hook(self, user)
request['AUTHENTICATED_USER']=user
request['AUTHENTICATION_PATH']='/'.join(steps[:-i])




# Remove http request method from the URL.
request['URL']=URL


とりあえず無視。

# Run post traversal hooks
if post_traverse:
result = exec_callables(post_traverse)
if result is not None:
object = result


お疲れ様。

return object

bloggerのウィジットがあったので入れた。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

#!/usr/bin/python2.4
print "hello prettyprint"


でどころ

2009年2月23日月曜日

nosetests --with-coverage(con't)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
noseの--with-coverage option

--with-coverage Enable plugin Coverage: If you have Ned Batchelder's
coverage module installed, you may activate a coverage
report. The coverage report will cover any python
source module imported after the start of the test
run, excluding modules that match testMatch. If you
want to include those modules too, use the --cover-
tests switch, or set the NOSE_COVER_TESTS environment
variable to a true value. To restrict the coverage
report to modules from a particular package or
packages, use the --cover-packages switch or the
NOSE_COVER_PACKAGES environment variable.
[NOSE_WITH_COVERAGE]

の実装をさらっと読んだ。


  • ソースをパースして実行されるstmtの辞書を作る。

  • sys.settraceを使って実行時にファイル・行情報を取り出して実行されたマークをつける。



ソースは1000行だし、compiler moduleを使ったことがあるのでやっていることはすぐわかった。sys.traceだが、ここを読むとすぐわかる。

3.1 sys -- システムパラメータと関数

settrace(tracefunc)
システムのトレース関数を登録します。トレース関数 はPythonのソースデバッガを実装するために使用することができます。 9.2の``How It Works,''を参照してください。 トレース関数はスレッド毎に設定することができますの で、デバッグを行う全てのスレッドでsettrace()を呼び出し、ト レース関数を登録してください。 注意: settrace() 関数は,デバッガ,プロファイラ, カバレッジツール等で使うためだけのものです. この関数の挙動は言語定義よりも実装プラットフォームの分野の問題で, 全ての Python 実装で利用できるとは限りません.


testをpass/failの赤いバーが緑になるunittestではなくて、uncovered, fail, passで2回変化すると面白いかも。

つぼにきた

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
クール観の違い, ゲーム開発における日米の違い

で、採用の基準になってる「クール」ってなんなのよ、って話。あるアメリカ人デザイナ曰く「ゲームにおいて、すべての人間は殺されるべきだし、すべての建造物は破壊されるべき。それができないゲームはサック」と。俺は内心「わー、このヒト気違いだわー」と思った。だが、その発言を受けて周りのデザイナが「すべてのゲームにもっと流血を!もっと爆発を!」とシュプレヒコールをあげるのを前に、彼らなりの共通認識を受け入れざるを得なかった。というか、北米市場に出回るゲームを見れば、彼らがいかにそれらを求めているか容易に確認できる。たぶん、日本人が「侘び寂び」の感覚を共有しているように、彼らの魂は硝煙と血の臭いでつながっているに違いない。死体のリアルな挙動や、おっさんのリアルな血管やヒゲなど、俺にはどうしてそこまで情熱をかけれるのか、と不思議なことも、彼らにしたら当然追い求めるべきことのようであった。そして、重要なことだが、ユーザーも同じくゲーム会社がそれらを追い求めることに何の疑問も抱いていない。

はい、私は遊んでるときなんでも壊そうとしました。ざんげします。そして正しかったことを今知りました。てか、そういう発想じゃなきゃGTAとかpostalとか作らないよな。GTAもpostalももって無いけど。古くはDoomとかQuakeとかMarathonとかのいわゆるFPSだよね。いまはFPSのチーム試合のTV放映とかあるのかな?

個人的に名作だと思うのはPopulousとSim City、A列車で行こう3(PS2で出したやつはジャンク)とか。

駄目だこりゃ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
気が向かなかったので、「システムはなぜダウンするか」を読んだ。
こんなもんかぁという感じですが、あまりも読み物しすぎ。

失敗学なみの仕上がりではない。

あと、明らかに間違っている記述があった。データのvalidationをクライアント側で済ませてしまおう、みたいなくだりがある。正しい値を入れることをアシストするのはやってもいいけど、クライアントに検証を任せてもよいのは、「クライアントが信頼できかつサーバクライアント間の通信経路を守れるとき」だけだ。web越しなら信用できることはないし、内部犯行が怖いなら、クライアントと通信経路は常に信頼できない。悪意のあるだれかがNotePCにアレ気なツール満載して、ネットワークに勝手につないで「残業」してくれたりすると困るからねぇ。

メインフレーム/汎用機の話とかが出ていて、銀行とかの中の人系かなぁとも思う。新生銀行は中身が違うらしいが。複数のマシンを用意してそれらを使い捨てにできる状況ならソフトウェアの作りやすさや人間に注目すべきだ。メインフレームetcはコンピュータに作業員が付属してきた時代のデザインだ。

html上のsource code(cont'd)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
SHJS - Syntax Highlighting in JavaScriptとか使うと楽そう。omoさんがBespinコードを読んでsyntax highliting pluginつくったらどーよとか書いていたなぁ。

組み合わせるのって可能なんだろうか?まずライセンスが違うよね。SHJSはGPLv3だし、BespinはMozilla Public License(MPL)だ。混ぜるとどうなるんでしょ。そもそもにjsがGPLってどういうことが現実としておきるのでしょう?GPLなjsimportしたhtmlのライセンスへの影響とか。

修正BSDライセンスApache Lincese 2.0にしてれれば悩まずすむのに。

あーあとjsはどこに一般的なライブラリというか、コード集積所があるのやら。
pythonならPyPIだし、PerlならCPAN、vim scriptならvim orgにある。

よくまとまってるページ

2009年2月22日日曜日

nosetests --with-coverage

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
まあまあというところか。decoratorの関係で、tgが全部入ってくるのは勘弁してほしい。
でかいものをこまめに通すのはあまり実用的ではない。あまりに情報量が多いから。
もっと早く使ってれば・・・。ドキュメントはちゃんと読みましょう。中がどうなっているか読んでみたいなぁ。Zope/Ploneも読みたいし。山盛りだ。

bglib 0 0 100%
bglib.depot 0 0 100%
bglib.depot.base 64 38 59% 28, 32, 35, 41, 44, 51, 55, 59, 62, 67-70, 76-78, 81-83, 86, 92, 97, 101, 103, 108-110
bglib.depot.cfg 36 26 72% 13, 32-42, 58
bglib.depot.dict 29 8 27% 11, 14-18, 21-22, 25-29, 32-33, 36-48
bglib.depot.lines 28 26 92% 13, 43
bglib.doc 16 10 62% 9, 11, 13, 17, 19, 21
bglib.doc.bgwiki 356 341 95% 20, 23-25, 122, 386-387, 410, 423, 436, 451, 557-561
bglib.doc.doctree 305 290 95% 26-28, 40, 47, 92, 224, 299, 350, 387, 418-419, 421, 423, 425
bglib.doc.fuzzing 102 52 50% 47, 50, 64-65, 77-78, 81-83, 86-131
bglib.doc.html 96 91 94% 49-53
bglib.doc.macro 380 368 96% 30, 34, 41, 127-135, 196
bglib.doc.mkdn 26 24 92% 48-49
bglib.doc.mock 6 6 100%
bglib.doc.rst 34 31 91% 71, 101-102
bglib.doc.viewer_type 23 21 91% 16-17
bglib.encoding 0 0 100%
bglib.encoding.FIBS 134 68 50% 75-78, 89-90, 102-110, 117-125, 131-135, 145, 149-150, 154-157, 161-167, 171-188, 192-193, 197-198, 201-202, 206-207
bglib.encoding.bearoff 46 36 78% 15-18, 39, 42, 79, 83, 85, 88
bglib.encoding.bearoff.gnubgdb 36 28 77% 43, 47-53, 72
bglib.encoding.bearoff.nori 41 36 87% 49, 62-63, 66, 69
bglib.encoding.bearoff.trice 38 36 94% 31, 61
bglib.encoding.dbbyte 69 61 88% 77, 83-84, 87, 96-100
bglib.encoding.gnubgid 174 141 81% 101, 109-110, 112, 135-140, 181, 195-198, 209-229, 257, 262, 265
bglib.encoding.gnubgpython 59 21 35% 27-38, 41-42, 45-46, 49-50, 53-55, 58-75, 78-79
bglib.gui 0 0 100%
bglib.image 0 0 100%
bglib.image.PIL 96 84 87% 38, 44-46, 53, 114-120
bglib.image.base 719 668 92% 61, 67, 91, 225, 230, 266, 280, 297, 467, 506-508, 534, 563, 618, 676-678, 712-722, 781, 790-795, 805-808, 834-845, 860, 942
bglib.image.css 125 124 99% 172
bglib.image.draw 67 56 83% 27-28, 37, 84-93
bglib.image.resource 0 0 100%
bglib.image.resource.deutsche 16 11 68% 21-25
bglib.image.resource.flower 16 11 68% 21-25
bglib.image.resource.kotobuki 16 11 68% 21-25
bglib.image.resource.matrix 16 11 68% 22-26
bglib.image.resource.minimal 16 11 68% 21-25
bglib.image.resource.nature 16 11 68% 21-25
bglib.image.resource.neon 16 11 68% 21-25
bglib.image.resource.safari 16 11 68% 21-25
bglib.image.theme 2 2 100%
bglib.model 0 0 100%
bglib.model.board 196 142 72% 44, 54-76, 81-82, 87, 118, 124-125, 129-130, 135-136, 140-141, 146-149, 158-159, 165-168, 171-172, 207-209, 216, 218, 227-229, 232, 236-239, 247
bglib.model.constants 29 29 100%
bglib.model.move 294 251 85% 22, 81-85, 130-133, 144-146, 200, 203-204, 208, 240, 278-279, 303, 319, 363, 387-389, 392-407, 411-412
bglib.model.util 50 43 86% 26, 37, 41, 51, 62, 70-71
bglib.protocol 0 0 100%
bglib.protocol.fibs 342 331 96% 35, 52, 54, 62-63, 80, 90-92, 471, 475
bglib.protocol.session 102 69 67% 44, 48, 73-74, 85, 95-112, 116-126
bglib.stat 0 0 100%

decorator

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
decorator
って、

from turbogears.decorator import weak_signature_decorator
def foo():
def entangle(func):
def bar(func, *args, **kws):
return func(*arg, **kws)
return weak_signature_decorator(entangle)


とinterfaceが違っぽい。どーなったんだ?!調べるのは昼寝してからしよ。眠い。

先日の調査の成果を生かして小奇麗にしてみた。まだまだいじる余地はありそうだ。もうちょっとやったら変換スクリプトでも書けばいい。

nosetests

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
noseを複数のversionのpython使いたい。書いたコードがほかのversionのpythonでも機能するかテストしたいから。

Linuxではシンプル。
/usr/bin/nosetestsを見ると、こうなっている。つかうpythonインタプリタを明示的に指定すればいい。#!/usr/bin/pythonからして当然だが。

#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'nose==0.10.3','console_scripts','nosetests'
__requires__ = 'nose==0.10.3'
import sys
from pkg_resources import load_entry_point

sys.exit(
load_entry_point('nose==0.10.3', 'console_scripts', 'nosetests')()
)


windowsではよくわからない。まあでもnosetestsのscriptをpythonインタプリタに渡してあげればよいようだ。

C:\Python24\Scripts\nosetests.exeとC:\Python24\Scripts\nosetests-script.pyが存在。なんだかねぇ。

#!c:\Python24\python.exe
# EASY-INSTALL-ENTRY-SCRIPT: 'nose==0.10.4','console_scripts','nosetests'
__requires__ = 'nose==0.10.4'
import sys
from pkg_resources import load_entry_point

sys.exit(
load_entry_point('nose==0.10.4', 'console_scripts', 'nosetests')()
)


2.5も入っている。

#!c:\Python25\python.exe

from nose import main

main()

2009年2月21日土曜日

2.6.28.6

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
にあげたらbootしない。進むにせよ、退くにせよ、keyboardとdisplayを直つなぎしないといけないからめんどくさい~~。さきにVMWareの上で確認してからにすればよかった。

2009年2月20日金曜日

upした。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
python2html.pyからどうぞ。いちおう、w3c validらしい。

form.add_file(buf,
content_type='text/xml; charset=us-ascii',
name='uploaded_file', filename='test.xml')

の部分とか怪しいけど。

コンテントタイプをサーバ側でちゃんとセットして無いから、あなたのブラウザがhtmlだと勘違いするかもしれません。あしからず。

source code in html

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
copy and pasteで正しく取り扱えて、行表示ができて、たぶんvalidなhtmlにできるものを思いついた。長すぎる識別子はどーにもならない。あとは行番号をpaddingしてindentにずれがあるようにならないことだ。

はーめんどくさ。

追記:
IE8だとline:7とかもcopyされてしまいます。FireFoxだとされません。まあ、もう救いようが無いな。code:beforeを無効化すればいいのでjavascriptでがんばる、もしくはブラウザによって打ち分けるhackを仕掛ければよいでしょう。

追記2:
contentは1つ目にcounterを、2つ目のオプション引数にformatを取れる。formatはlist style typeを指定できる。まあ、当然decimal-leading-zeroを指定すればいい。



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
  <title>test</title>
<!-- http://www.w3.org/TR/CSS21/text.html#white-space-prop -->
<style type="text/css">
<!--
body {
    counter-reset: lineno;
}
.codeblock {
    white-space: pre;
    white-space: pre-wrap; /* CSS3 */
    white-space: -moz-pre-wrap; /* Gecho(FireFox, Mozilla) */
    white-space: -o-pre-wrap; /* opera */
    white-space: -pre-wrap; /* old */
    word-wrap: break-wrap; /* IE5.5 or later + Safari */
    background: red; /* debug color */
    width: 500px; /* narrow space */
}
code:before {
    content: 'line:'counter(lineno)' ';
    counter-increment: lineno;
}


-->
</style>
  </head>
<body>
<pre class="codeblock">
<code>import sys</code>
<code></code>
<code>def foo(x):</code>
<code>    return x+x</code>
<code></code>
<code>print foo(2)</code>
</pre>
続き。
<pre class="codeblock">
<code>def bar(y):</code>
<code>    return y*2</code>
<code></code>
<code>print foo(2), bar(3)</code>
</pre>

<pre class="codeblock">
<code>def thisisveryverylongfunctionname(x):</code>
<code>    return x**2</code>
<code></code>
</pre>
</html>

2009年2月19日木曜日

html上のsource code

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
code elementなるものがあるが、実際のところ、使われ具合は微妙なようだ。

普段思わずやってしまう、programのsource code全体をcode elementに入れておいて、インデントが破壊されると文句を言うのは筋違いのようだ。事実、code elementはinline elementであって、block elementじゃない。

2002とちょっと古いが、html4に対応しているからいいだろう。ちょっと不思議なテキストレベルの要素タイプ の「2.1 CODE要素タイプ」によれば

これによると、codeはプログラム内の式を引用したり、変数、関数、プログラムの名前といったキーワードをマーク付けするときに利用できることが分かります。たとえばHTMLについて説明する本稿のような文書なら

強調要素タイプには<code>em</code>と<code>strong</code>があります。


といった使い方が考えられるでしょう。


一方で、html原理主義者としてとしてどーのこーというより、とにかく見た目が綺麗で、裏にあるdbのデータを流し込みやすいことが大事なときがある。とくに行番号を表示したい、かつcopy&pasteでコードを流用しやすいようにしたいとなると、状況が悪化してくる。

結局tableを使うかどうかのようで、使う場合にはtableの中にpreが入れ子になる。preのblockを左右に並べる手もあるだろうが、windowをリサイズされると、codeを含んだpreが行番号のpreの下に行って崩れるのかな。幅を指定したblockで囲めばよいのだろうが、agentしだいだね。コードのpreの幅は、まあ80文字固定で問題ないだろう。それで困るならそのコードは見るに値しないから、htmlにする必要もなさそう。ネタのonlinerとかは違うだろうが。逆に1行80文字の幅が確保できない環境でsourceを表示することはそもそもに無理があるのだろう。そうなるとどう妥協するかだ。

  • table+pre派

    • pros: copy&pasteがうまくいく

    • cons: tableじゃないものをtableでレイアウト。

  • 1行にline番号とソースを置く派

    • pros: htmlとしてはOK

    • cons: ソースコードがtextとして連続でなくなるのでcopy&pasteが破綻する。

codepadとかのhtmlは読めるけど、ajax全盛なのでしらべるのめんどくさい。

それをいっちゃあおしまい的なことを書くと、outputの形が不定寸法になるhtmlで、印刷物のような綺麗なlayoutをしようとすること自体無理がある。htmlの底流に流れている思想は、「横幅が足りんかったら下へ下へ」なのだ。印刷物の場合は、fillできるboxが幾つか並んでいて、最初のboxにtextを流し込んでそれであふれたら次のboxに入れていく、boxは絶対座標で指定という思想だ。QuarkXPressとかPageMakerとかいったDTPソフトはそういった、boxへの流し込みをサポートしている(その昔、Wordで2カラム構成をとるのに全角スペースを二個真ん中に入れて、手動で2カラムした怪力の人を見たことがあったなぁ・・・)。ましてや複数Page化するとhtmlはお手上げだ。おそらく印刷関係者から見ると、これとかは同じ考えだろう。そんなに厳密なlayoutがほしいならpostscriptやpdfを使うべし。


最後にJoke:
普段私が触れるtextって左から右なんですが、世の中の言語にはその逆なのもあるので右から左にもできる。具体的にはヘブライ語やアラビア語だ。一方で、プログラミング言語でRtoLなやつは私が不勉強なせいもあってきいたことが無い。

2009年2月17日火曜日

ぷちぷち?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

  • リリースエンジニアリング

  • よくあるソフトウェアのデザイン不良

    • 複数あり得るものを一つしかないと思い込んだ

    • 何が嬉しいか分からなくてもいいから、全部複数あるものとして扱え



    「1つ作るなら2つ作れ」
    -- SRハデン(映画:コンタクト)

    を思い出した。シングルトンじゃないなら常に複数個?

  • Pythonコードの品質管理
    そうか、metricaがんばろー。
    ああ、単語がらみの辞書のformatメモ

    let me see 辞書
    EBライブラリを使っているので、EPWING形式なら何でも。


  • Pythonの謎3kで解決されたはず。型が違うと比較がそもそもに許されない。


  • 「ソースコードを公開したから世界に普及した」——米Zope CEO Robe Page氏

    Zope2の、Data.fsさえコピれば同じ環境が手に入る手軽さを考えると、疑問に感じてしまいます。

    sqliteにも同じ現象が見られる。世の中、fileをseekしたくないのだろう。
  • 名前空間とファイル構成
    よく使う手。tonic.cache.impとか

    #!/usr/bin/env python
    # -*- coding: us-ascii -*-
    # vim: syntax=python
    #
    # Copyright 2008 Noriyuki Hosaka bgnori@gmail.com
    #

    __all__ = ['Null', 'Dict', 'Disk', 'File',
    'Memcache', 'Hierachy',]

    from tonic.cache.imp_null import Storage as Null
    from tonic.cache.imp_dict import Storage as Dict
    from tonic.cache.imp_disk import Storage as Disk
    from tonic.cache.imp_file import Storage as File
    from tonic.cache.imp_memcache import Storage as Memcache
    from tonic.cache.imp_hierachy import Storage as Hierachy


2009年2月16日月曜日

やっていてたのしいのか?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
プログラムを書くことは楽しいか?・・・微妙。

たのしいかどうか、というよりやらずにはいられない、プチプチがあるとつぶしたくなる類のもの。

backgmmonbaseのためのスクラップ・メモ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
世間の流行とか日記とか

trackbackも同等に面倒くさすぎ。私は全然使わない。個人的には、trackbackは根本的にやり方が間違っていると思う。何か書きたい記事があったら、「この記事に対して何か書く」みたいなリンクがあって、それをクリックしたら、即編集画面に移って、編集を終えたら、trackbackも完了、ぐらいじゃないとやってられない。もっとも、こいつは相互運用の問題でもあるので、どう解決すべきなのかは判然としないのだが。

unittestの自動生成

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

----------------------------------------------------------------------
Ran 8301 tests in 4.363s

OK

やっていることがあんまり正しく無い気もした。

フリーかどうかは関係が無い。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ソフトウェアのマーケティングの話。
キャズマとか、アーリーアダプターとか。

GNU十周年

Backup

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
株式会社はてなの開発戦略を読んでいてバックアップしなきゃいけないことに気づいた。そしてサーバのbackupをした。過去にいろいろ調べたが、現在は大事だと思うdirectoryをtar gzipしているだけ。dbはsnap shotをとっている。まとめてローカルのPCに落とし、さらにCD-Rに焼いている。ほんとうはlvmのvolume snap shotをとってからやるべきだろうが。面倒くさいしごみを消すのがアレなので。

そんなことよりもsnap shotのsizeが700MBなのでそのうちにCD-Rに収まらなくなる。どうしたものか。


P.S. メモ帳に次のスケジュールを入れたよ。

追記:
svnのrepositoryを吹っ飛ばしたくだりをdisっている話で、失敗を開けっぴろげにできるのはいいという主張があったが、失敗は隠せということか。

OMake

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
OMakeん~どーなんでしょ。RPMが古かったから試すのやめた。だいたいbuild不要だし。nosetestをkickさせてもいいけど、むやみやたらにunittestされてもうるさいだけなんだよね。

これも富豪的プログラミングの一種だね。ただoutputの垂れ流しに人間が耐えられない。それこそBMIでダイレクトに脳みそにデータを送るとかいうことにでもなら無い限り、いかにoutputを減らすか、outputを必要とするタイミングをなくすかがUIのデザインの肝では無いかと思う。古のプログラマが給料のために行数を水増したように糞logなんていくらでも作り出せるのだから。

そういえばビジュアライジング・データ ―Processingによる情報視覚化手法 (大型本)の訳者は・・・。

きっとログやデータを大量に発生させてそれに対処する需要を生み出そうという陰謀にちがいない(んなわけない)

2009年2月6日金曜日

そういうもんだ。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
そろそろ例のプロジェクトについて言及するか


まず、ソースコードが大雑把に見積もって3750万行あるのだけど、その中でまともに機能しているコードは3%しかない。10分の1程度のソースコードで同程度の機能を実現しているシステムもあるのでほんとあのシステムのコードはゴミだと言っても過言じゃない(*1)

よのなかそういうもんだ。

bonanzaのソースコード公開

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ボナンザのソースが公開されたらしい。なんかwindows用だぞ?

http://d.hatena.ne.jp/yaneurao/20090128経由。もとはだんこがいのblogを見ていたのだが。

wcの結果。3万行。

319 996 7883 attack.c
373 1603 8156 bitop.c
282 1313 8821 bitop.h
wc: bonanza.ico:1: Invalid or incomplete multibyte or wide character
0 3 4286 bonanza.ico
1 3 27 bonanza.rc
426 2364 15889 bonanza.txt
1230 4749 31125 book.c
965 3339 23403 csa.c
319 1251 10289 data.c
242 1464 9756 debug.c
314 914 6914 dek.c
216 790 5601 evaldiff.c
418 1653 11116 evaluate.c
460 1552 11232 gencap.c
1354 4425 35192 genchk.c
194 952 6189 gendrop.c
651 2857 18938 genevasn.c
370 1298 9698 gennocap.c
1163 4075 30909 hash.c
1089 4102 31387 ini.c
754 2377 15852 io.c
836 3041 23106 iterate.c
1076 3799 26458 learn1.c
860 3346 22022 learn2.c
142 434 2931 main.c
80 346 2654 Makefile
94 364 3077 Makefile.vs
506 2057 18841 makemove.c
2155 8155 70520 mate1ply.c
689 2448 17837 mate3.c
415 1346 11942 movgenex.c
340 1098 9124 next.c
15 81 551 param.h
80 282 1937 ponder.c
102 427 2917 problem.c
1463 5198 32798 proce.c
233 771 5552 quiesrch.c
87 298 1619 rand.c
249 957 6172 root.c
369 1121 7365 sckt.c
1346 4725 35610 search.c
744 2607 17984 searchr.c
1324 5932 50146 shogi.h
391 1330 9606 swap.c
452 1250 10829 thread.c
286 1082 6566 time.c
326 1366 14126 unmake.c
634 2333 16741 utility.c
197 844 5285 valid.c
26631 99118 736979 total


ぱっと見悪いコードではない。メンテナンスして開発が続けられる以上、当然か。

csa.cは棋譜をやり取りするためのモジュール。
hash.cとかはアレげだけど、モジュールの性質を考えたら当然か。

buildはさっくりできました。
cのrestrictをmacroでundefしたらだけど。gccに-std=c99を渡すと今度はbuildできない。-std=gnu99しなさいということらしい(ビルド成功)。まあ、アプリとして動かすのはがんばらないといけないだろうけどね。

2009年2月4日水曜日

macports 後始末

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
結局全消し、入れなおしした。orz.

つーかそれじゃぁ微妙なんだよね・・・なんでpackage管理システムを使っているのかわからない。どのportsが使われているかのリストだけでも残さないと。CentOSのではyumで入れたやつをyum listかなんかでbackup時に記録している。macportsもport info activesとかで保存すべきなのかもしれない。variantとか細かい話が残るが・・・。

唯一の救いといおうか、いつまでも質が上がらない原因というか、環境が完全に破壊されてすべて入れなおしにならないんだよね>macports. CentOSのyumはそうは行かない。yumで入れてるpythonを消すと再起不能になる(yumはpythonで実装されているため)

macportはけしてもMacOS Xのsafariがあるしどうにかなる。
あーあ。ploneを入れるのは先になりそうだ。というかploneはportsに入っているのか?

macports

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
久々にupgradeしたらdiskを食い尽くして死んでしまった。やれやれ。

2009年2月3日火曜日

sys.stdoutをbinaryでかく。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
cgiでsys.stdoutへの出力がcp932で出てしまって困った人への回答@mixi

それなりにがんばって書いたのと、前の発表の内容のリサイクルが含まれるのでおいらが書くのが相当かとおもって書いてみました。コード書いたほうがいいかもね。でもまったくAPIが無いのも変だな。もうちょっとちゃんと探すべきかも。

追記あり。

http://coreblog.org/ats/article-of-python3-at-atmark-it
http://www.atmarkit.co.jp/fcoding/articles/python3/01/python301b.html
の話かな?


> print(b'文字列')も一応は試したのですが、これもTypeErrorを出したように記憶しています。また後日、試してみます。

b'...'は文字列ではないです。byte列です。:)
encodingがないのです。逆にbを指定しないものは文字列なので、encodingを持っています。

i.e.
>>> x = 'ほげ'
>>> x
'ほげ'
>>> x.encode('utf8')
b'\xe3\x81\xbb\xe3\x81\x92'

で、
>>> sys.stdout
<io.TextIOWrapper object at 0x7f6a78342690>
といわれます。

textモードで開いたfile objectはエンコードを持っています。
http://git.tonic-water.com/works/PythonCodeReading/2.5to3ofStdLib/PCR07.swf
クラス図はこちら
http://git.tonic-water.com/works/PythonCodeReading/2.5to3ofStdLib/io-class.dia

私の環境では、
>>> sys.stdout.encoding
'UTF-8
>>> locale.getpreferredencoding()
'UTF-8''
>>> print(sys.stdout._encoder)
<encodings.utf_8.IncrementalEncoder object at 0x7f6a7824a9d0>

>>> print(sys.version)
3.0+ (unknown, Jan 9 2009, 23:24:15)
[GCC 4.1.2 20071124 (Red Hat 4.1.2-42)]

uname -a
Linux asama 2.6.28.2 #28 SMP Tue Jan 27 15:03:26 JST 2009 x86_64 x86_64 x86_64 GNU/Linux
env.
LANG=en_US.UTF-8

念のためwindows xpのコマンドプロンプトから3.0を実行してみたところ、
sys.stdout.encodingはcp932でした。
>>> print(sys.stdout._encoder)
<encodings.cp932.IncrementalEncoder...>
なのでまあ、当然cp932を吐くでしょう。

となると・・・行儀よく清く正しいsys.stdoutのencoderの差し替え方がなんであるかが、問いですね。もしくはsys.stdoutをbinaryで開いて、utf8で明示的にencodeしてbyte列を生成して書き込むかですね。

さすがに
>>> sys.stdout.buffer.raw
_fileio._FileIO(1, 'wb')
にたいしてwriteするのはどうかと・・・。

なので、encodingがTextIOWrapperで付与されていることに着目して、
>>> print(codecs.getwriter('utf8').__init__.__doc__)
Creates a StreamWriter instance.

stream must be a file-like object open for writing
(binary) data.

stdoutのTextWrapperを「剥いて」あげてからStreamWriterのコンストラクタに渡してみるのはどうでしょう。

ということは
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
では駄目でしょうね。encoderが二段重ねになるので。


追記


sys.stdout.bufferを使うのが正しい。気持ち悪いが。

http://docs.python.org/3.0/library/sys.html#sys.stdout


Note

The standard streams are in text mode by default. To write or read binary data to these, use the underlying binary buffer. For example, to write bytes to stdout, use sys.stdout.buffer.write(b'abc').

pc x server

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
傀儡師の館.PythonX端末のエミュレータ

starnet

StarNet's mission is simple: Make a PC X Server that increases end-user productivity through performance, ease of use and innovative productivity-enhancing features ... and make it affordable!

plone

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ploneをいじることにした。

それ自体が$になりやすいことと、object db何ぞや~~とか、フレームワークとしても興味深い。まずはwww.tonic-wate.comのtop pageをploneを使ったものに移行するとかかな。いまは素の手書きhtmlだし。そろそろ限界だ。

まずはインストールなんですが、yumのrepositoryには2.0と3.0があるのに触るのは2.5で、配布サイトにはrpmが無くてオレオレインストーラがあったりします。

2009年2月2日月曜日

メモ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
modelとdb上でのデータの型がちがう。i.e. encodingみたいなものを持っている。


  • sqlobjectでがんばるならpropertyのようなトリックを使ってmodelとしてはencodeしたものでもち、propertyアクセス時にdecodeする。(なんかそういうhookをするためのAPIがあった気もするが)

  • sqlalchemyでmapするときにhookするかな。


どちらも調査が必要だ。