[pukiwiki]
[[こちらの記事の続き:http://boxheadroom.com/2009/10/14/mathlink_weatherdata_1]]
無料のMathematicaPlayerをIronPython2.6RC1を使い、Webアプリとして動かしてみました。
こちらの記事を参考にしてさせて頂きました(というか、ほぼ引き写し)
-[[無料配布MathematicaカーネルとNET Framework実装IronRubyでグリッド・Matheatica計算環境は5分で作れる:http://www.hirax.net/diaryweb/2009/10/06.html#8400]]
-[[WSGIとPythonでスマートなWebアプリケーション開発を 第3回 WSGIミドルウェアの作成:http://gihyo.jp/dev/feature/01/wsgi/0003]]
-[[Python ライブラリリファレンス wsgiref — WSGI ユーティリティとリファレンス実装:http://www.python.jp/doc/2.5/lib/module-wsgiref.html]]
すごく久々にサーバのスクリプトを書きました
[/pukiwiki]
[pukiwiki]
ホントは、何か既存のWebフレームワークを使おうと思ったのですが、頭がこんがらがったので上記の記事を参考にしてテキトー作成。
localhostからのアクセスしか考えてないので、セキュリティ周りははしょってあります。(というか、どうしたら安全なのか判らず)
あくまで自分の勉強用コードということで。。。
*使い方
コマンドプロンプトにて
ipy MathematicaServer.py
として起動。
http://localhost:8000/evaluation/式
式をMathematicaPlayerで評価
プレーンテキストとして結果が返ってきます。
/restart MathLinkを再起動
/shutdown サーバを終了
CPythonからWeb API経由で呼び出すためのモジュールを書くとCGソフトのBlenderなどからも使えて便利かも。
(分散処理しないなら子プロセスのほうが簡単だったかしらん?)
例)
http://localhost:8000/evaluate/WeatherData[{“Gifu”,”Japan”},”Temperature”]
14.4 #岐阜の現在気温 14.4℃が返ってきました。
以下コード
[/pukiwiki]
まずは、URLに応じて関数を呼ぶためのディスパッチャ(WSGIのミドルウェア)とユーティリティ関数。
app.pyとして保存。
こちらは、IronPythonでもCPython2.5でも動きました
#-*- coding:utf-8 -*- """ app.py original source WSGIとPythonでスマートなWebアプリケーション開発を 第3回 WSGIミドルウェアの作成 http://gihyo.jp/dev/feature/01/wsgi/0003 """ from wsgiref import util, simple_server class const(object): name = 'SCRIPT_NAME' info = 'PATH_INFO' def header(start_response): start_response('200 OK', [('Content-type', 'text/plain')]) def notFound(environ, start_response): start_response("404 NotFound",[('Content-type', 'text/plain')]) return '%s is not found' % util.request_uri(environ) class SelectApp(object): u''' パスによるアプリケーション振り分け''' def __init__(self,notfound=notFound): # 割り振るパスが見つからなかったときに呼び出すアプリケーション self.notfound = notfound self.table=[] self.flag=True def dispatch(self,path): def _(app): self.table.append( (path,app)) return app return _ def __call__(self, environ, start_response): u''' リクエストのパスを見て振り分ける ''' scriptname,pathinfo=name_info(environ) for p, app in self.table: if p == '' or p == '/' and pathinfo.startswith(p): return app(environ, start_response) if pathinfo == p or pathinfo.startswith(p) and \ pathinfo[len(p)] == '/': fetchone(environ,p) #scriptname,pathinfo=name_info(environ) return app(environ, start_response) return self.notfound(environ, start_response) def name_info(environ): scriptname = environ.get(const.name, '') pathinfo = environ.get(const.info, '') return scriptname,pathinfo def fetchone(environ,p=""): scriptname,pathinfo=name_info(environ) if not p: plist=pathinfo.split("/") p=plist.pop(0) scriptname+= p pathinfo=pathinfo[len(p):] environ[const.name] =scriptname environ[const.info] = pathinfo return p
こちらはIronPython専用
MathematicaServer.pyとして保存。
#-*- coding:utf-8 -*- """ MathematicaServer.py original source 無料配布MathematicaカーネルとNET Framework実装IronRubyで グリッド・Matheatica計算環境は5分で作れる http://www.hirax.net/diaryweb/2009/10/06.html#8400 """ import clr , System require=clr.AddReferenceToFile #require=clr.AddReferenceByName require("Wolfram.NETLink") from Wolfram.NETLink import * import sys from app import * from wsgiref import simple_server mlpath="-linkmode launch -linkname " #full path to mathkernel.exe mlpath+=" 'C:\\Program Files\\Wolfram Research\\Mathematica Player\\7.0\\mathkernel.exe' " class Mathematica(object): def open(self): self.kernelLink=MathLinkFactory.CreateKernelLink(mlpath) self.kernelLink.WaitAndDiscardAnswer() def do(self,command): return self.kernelLink.EvaluateToInputForm(command, 0) def close(self): self.kernelLink.EvaluateToInputForm('MVClose[]', 0) self.kernelLink.Close() app = SelectApp() dispatch=app.dispatch @dispatch("/restart") def restart(environ,start_response): header(start_response) m.close() m.open() return "OK" @dispatch("/evaluate") def evaluate(environ,start_response): scriptname,pathinfo=name_info(environ) if pathinfo : ret= m.do(pathinfo[1:]) header(start_response) return ret else : return notFound(environ,start_response) @dispatch("/shutdown") def shutdown(environ,start_response): app.flag=False header(start_response) return "Shutdown" if __name__ == '__main__': import threading,time def watch(): while app.flag : time.sleep(1.) m=Mathematica() m.open() srv = simple_server.make_server('127.0.0.1', 8000, app) th=threading.Thread(target=srv.serve_forever) th.setDaemon(False) w=threading.Thread(target=watch) w.setDaemon(True) w.start() th.start() w.join() th.join(1.) sys.exit()
shutdownまわりがゴチャゴチャしております。