Hatena::Groupfukuoka-py

ikikko.py このページをアンテナに追加 RSSフィード

2008-12-15

DLLをスクリプト上で読込

22:42 |  DLLをスクリプト上で読込 - ikikko.py を含むブックマーク はてなブックマーク -  DLLをスクリプト上で読込 - ikikko.py  DLLをスクリプト上で読込 - ikikko.py のブックマークコメント

PythonからActiveX(on Trac Lightning) - ikikko.py - fukuoka.pyのはてなグループでやったんだけども、やっぱりユーザに事前にDLLをセットさせるなんてことはやらせるのもどうかなと。極力、プラグインは事前準備無しで動くようにしておきたいものですし。

じゃあどうすればいいかなというと、スクリプト上で動的にDLLを読み込みばいっかと。動的に指定する分若干遅くなりそうだけど、無視できる程度でしょう、多分w


今回参考にしたサイトはこちら。

手順としては、

  1. TracLightningをインストールすると自動で登録される環境変数「TRACPATH」を引っ張ってくる
  2. 1で引っ張ってきたパス以下を「os.walk」で順次参照する
  3. 「pythoncomXX.dll*1」が見つかったら、その時点で「os.walk」を抜ける
  4. 「pythoncomXX.dll」のパスを引数に、「ctypes.windll.LoadLibrary」を呼び出す

実際に試してみると、こんな感じ。

#/usr/bin/env python
# -*- coding: utf-8 -*-

import ctypes
import os
import re


def __getpythoncompath():
    """ Return 'pythoncomXX.dll' path."""
    pattern = re.compile("pythoncom\d{2}\.dll")

    for tracpath in os.environ.get("TRACPATH", "").split(";"):
        for dpath, dnames, fnames in os.walk(tracpath):
            for fname in fnames:
                if pattern.search(fname):
                    return os.path.join(dpath, fname)

ctypes.windll.LoadLibrary(__getpythoncompath())
import win32com.client


if __name__ == '__main__':
    excel = win32com.client.Dispatch("Excel.Application")
    excel.Visible = True
    excel.Workbooks.Add()
    excel.Cells(1, 1).value = u"初めてのExcel"

これで、DLLの事前セット無しにActiveXを使えるようになりましたと。

*1:XXはバージョン番号

IskeeIskee2012/02/22 17:38HHIS I should have tohguht of that!

2008-12-06

PythonからSubversion(on Trac Lightning)

23:08 | PythonからSubversion(on Trac Lightning) - ikikko.py を含むブックマーク はてなブックマーク - PythonからSubversion(on Trac Lightning) - ikikko.py PythonからSubversion(on Trac Lightning) - ikikko.py のブックマークコメント

作りたいものを実現するためのもう一つのハードルとして、PythonからSubversionを扱うための確認を。ただ、こっちは相当しんどかった。日本語・英語に限らず、ネットに転がっている情報が少ない!その中で、いくつか有用と思われる情報が載っていたサイトを集めてきました。

これも、できるだけTrac Lightningの環境を用いて実現しようとしたので大変だったのですが。pysvnというサードパーティのモジュールを使えば、もっと楽にできそうですね。(via 夜でもアッサム: pysvn - Subversion APIをpythonから使う


Subversionでやりたいこと

何はともあれコミット。欲を言えばチェックアウトと更新もやりたいのですが、これは最初は人力でやるということで、いったんは置いておく。

コミットでできる限り実現したいことは、コミットログ出力とコミットユーザの可変。ログ出力の重要性は言わずもがなとして、ユーザの変更を実現したい理由は、Pythonスクリプトを実行するユーザとコミット対象物の作成者が異なるから。異なるシステムで管理されているファイルをぶっこ抜いてきてSubversionにコミットするということを考えているから、コミットユーザは実際にコミットする人ではなくて元のファイルを作成した人にしておきたいのですよね。

コミットログ出力

コミットログを出力する方法はclient.pyのテストから。

def setUp(self):
  """Set up authentication and client context"""
  self.client_ctx = client.svn_client_create_context()

(中略)

  self.assertEquals(self.client_ctx.log_msg_baton3, None)
  self.assertEquals(self.client_ctx.log_msg_func3, None)
  self.client_ctx.log_msg_func3 = client.svn_swig_py_get_commit_log_func
  self.client_ctx.log_msg_baton3 = self.log_message_func

(中略)
def testMethodCalls(self):
  """Test direct method calls to callbacks"""

(中略)

  # You can also invoke the log_msg_func3. It'd be
  # nice if we could get log_msg_func3 function
  # to invoke the baton function, but, in order to do that,
  # we'd need to supply a value for the first parameter.
  self.client_ctx.log_msg_func3(None, self.client_ctx.log_msg_baton3)

log_msg_func3の第一引数のNoneは、多分tmp_fileのこと?確信は持てませんが、ドキュメント見るとそうっぽい。

コミットユーザ変更

任意のユーザでコミットするにはauth.pyのテストを参考に。

def test_credentials_get_username(self):
  def myfunc(realm, maysave, pool):
    self.assertEquals("somerealm", realm)
    username_cred = core.svn_auth_cred_username_t()
    username_cred.username = "bar"
    username_cred.may_save = False
    return username_cred
  baton = core.svn_auth_open([core.svn_auth_get_username_prompt_provider(myfunc, 1)])
  creds = core.svn_auth_first_credentials(
              core.SVN_AUTH_CRED_USERNAME, "somerealm", baton)
  self.assert_(creds is not None)

svn_auth_get_username_prompt_providerのAPIこちら。ここで第二引数の1はretry_limit、つまりリトライの回数を表しています。

コミット

コミットするには、svn_client_commit4を呼び出す。

svn_error_t* svn_client_commit4(
  svn_commit_info_t        **commit_info_p,
  const apr_array_header_t *targets,
  svn_depth_t              depth,
  svn_boolean_t            keep_locks,
  svn_boolean_t            keep_changelists,
  const apr_array_header_t *changelists,
  const apr_hash_t         *revprop_table,
  svn_client_ctx_t         *ctx,
  apr_pool_t               *pool
)  	

ctxが↑のログ出力とユーザ変更の設定を格納する変数。とりあえず今回は「keep_locks, keep_changelists, changelists, revprop_table」は何も設定しなくてOK。


ただ、ここまで来て今更ながら一つ疑問が。そもそも「baton」ってなに?

baton」ってなに?
Subversion のソースコードを通して、幾つもの「baton」オブジェクトへの参照が存在する。 これは、関数に対してコンテキストを提供するただのvoid*データ構造だ。他のAPIでは、これらはしばしば、void *ctxやvoid *userdataと呼ばれるが、Subversion の開発者は、この構造を「batons」と称している。 というのも、これらは相当数、引き回されることになるからだ。
subversion: Subversion FAQ (in Japanese)

よく分かりません…orz。もうちょっと調べる。

C APIの引数におけるコールバック関数とバトン(コールバック関数に渡すユーザデータ)ペアは、Python APIの引数ではファンクションオブジェクトのみに縮退する。すなわち、バトンは消滅する。ファンクションオブジェクトには、バトンを除くコールバック関数の引数が渡される。ユーザデータを渡したい場合は、Pythonのデフォルト引数を用いるべし。

no title

こっちの方がまだ何となく分かる。要するに、引数データということかな。


最後に、検証したことをテストしたスクリプトを。あー、疲れた・・・

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
from svn import fs, repos, core, client


""" client contextの作成 """
ctx = client.svn_client_create_context()

""" 1. コミットログ出力
       ユニコード文字列はエラーになる!
"""
def my_log_message_func3(items, pool):
    return "commit log" + "\n" + time.ctime()
ctx.log_msg_func3 = client.svn_swig_py_get_commit_log_func
ctx.log_msg_baton3 = my_log_message_func3
ctx.log_msg_func3(None, ctx.log_msg_baton3)

""" 2. コミットユーザ変更
       デフォルトユーザを使用する場合は、core.svn_auth_get_username_provider()
"""
def my_prompt_func(realm, maysave, pool):
    username_cred = core.svn_auth_cred_username_t()
    username_cred.username = "hoge"
    username_cred.may_save = False
    return username_cred
retry_limit = 1
providers = [
    core.svn_auth_get_username_prompt_provider(my_prompt_func, retry_limit),
]
ctx.auth_baton = core.svn_auth_open(providers)

""" 3. コミット """
path = 'C:/MyDocuments/Program/python/workingcopy'
keep_locks = False
keep_changelists = False
changelists = []
revprop_table = {}
client.svn_client_commit4([path], core.svn_depth_infinity,
                          keep_locks, keep_changelists,
                          changelists, revprop_table, ctx)

2008-12-02

標準のデバッガ機能

00:57 | 標準のデバッガ機能 - ikikko.py を含むブックマーク はてなブックマーク - 標準のデバッガ機能 - ikikko.py 標準のデバッガ機能 - ikikko.py のブックマークコメント

気がつけばこんな時間。今日一体何やってたんだろう…><

悔しいので、ちょっとでもアウトプットを出しておく。


そろそろ調査モードも抜けて、動くものを作っていかないと思っている今日この頃。ただ、勧めていく上で一つ気にかかることは、デバッグ環境。

いかんせん、Pythonプログラミングもまだ駆け出しなんで、やっていく内に様々なところで引っかかるのは目に見えています。その時の動作検証にEclipse(PyDev)のデバッガを使いたいけど、ちょっと厳しそう。

というのは、大本のプログラム作成は自宅でやるつもりですが、実際に意図した通りに動くかは(定時外で)職場で試すしかできないんですよね。となると、あまり大っぴらに作業ができない。もちろん、やることやってれば、定時外は個人の好きにしていいというのはあるでしょうが、皆がいる中で堂々と個人的な作業をやるのも…ね。

あまり大っぴらにはしたくないので、Eclipseなどをインストールするのもできれば避けたい。というわけで、前置きが長くなりましたが、標準のデバッガを使わざるを得なさそう。

モジュールpdbPythonプログラム用の対話的ソースコードデバッガを定義します。(条件付き)ブレークポイントの設定やソース行レベルでのシングルステップ実行、スタックフレームのインスペクション、ソースコードリスティングおよびいかなるスタックフレームのコンテキストにおける任意のPythonコードの評価をサポートしています。事後解析デバッギングもサポートし、プログラムの制御下で呼び出すことができます。

404 Not Found

うーん、なるほど。インタラクティブシェルといい、Pythonはこういった類の開発環境が充実していると思います。

ただ、EclipseGUIなデバッガに慣れた身としては、CUIなデバッガは正直敷居が高いんですよねorz。ま、そんなことを言ってる場合じゃないか…

2008-12-01

PythonからActiveX(on Trac Lightning)

00:33 | PythonからActiveX(on Trac Lightning) - ikikko.py を含むブックマーク はてなブックマーク - PythonからActiveX(on Trac Lightning) - ikikko.py PythonからActiveX(on Trac Lightning) - ikikko.py のブックマークコメント

もっと頻繁に書いていくつもりだったのに、いつの間にか最初のエントリから結構過ぎてました。気合入れんと!


作りたいものを実現するために、PythonからActiveXを使う際の動作検証。ただ一点だけ制約事項は、できるだけTrac Lightningの環境をそのまま用いて実現すること。

まずは、手始めに PythonからActiveXを使ってExcelとIEを操作する例 - ふにゃるんを参考にしてExcelを扱ってみる。

#!/usr/bin/env python
# coding: utf-8

import win32com.client

if __name__ == '__main__':
    excel = win32com.client.Dispatch("Excel.Application")
    excel.Visible = True
    excel.Workbooks.Add()
    excel.Cells(1, 1).value = u"初めてのExcel"

うーん、速攻でエラーが。よく分からないので、少しずつ切り分けてみることに。そうしたら、↓が大本の原因らしい。

>>> import pythoncom
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\TracLight\python\lib\site-packages\pythoncom.py", line 3, in <module>
    pywintypes.__import_pywin32_system_module__("pythoncom", globals())
  File "C:\TracLight\python\lib\site-packages\win32\lib\pywintypes.py", line 94, in __import_pywin32_system_module__
    "No system module '%s' (%s)" % (modname, filename)
ImportError: No system module 'pythoncom' (pythoncom25.dll)

「pythoncom25.dll」がねーよと。うーん、どういうことだろうと、提供元サイトのFAQを見てみる。

Check for duplicate Python system files Check for multiple versions of pythonxx.dll, pywintypesxx.dll, or pythoncomxx.dll, where xx is the Python version (eg, 23). In general, you should find exactly one copy of these files in your Windows system directory (generally named SYSTEM32.) However, non admin installs will place then in your main Python directory. Check for copies of these files in both places - if you find multiple copies, delete all but the ones in your system directory.

403 Forbidden

要するに、本来ならWindowsシステムディレクトリかPythonのメインディレクトリのどっちかに放り込まれるよと。けど、どっちも見当たらないね…。けど、どっかにありそうな気がするんですよね。なんで、TracLight以下のディレクトリを全部検索してみる。

「C:\TracLight\python\Lib\site-packages\pywin32_system32」に「pythoncom25.dll」があった!これを、とりあえず↑のどっちかのディレクトリに放り込めばいいのかな?やってみよう。

・・・でけた!一番最初のスクリプトを実行すると、こんな感じにExcelが勝手に立ち上がる!!ブラボー!おお…ブラボーw

f:id:ikikko:20081202002213p:image

LenemarLenemar2013/02/01 16:48What an awesome way to explain this-now I know everytnihg!

2008-11-17

まずは

01:05 | まずは - ikikko.py を含むブックマーク はてなブックマーク - まずは - ikikko.py まずは - ikikko.py のブックマークコメント

自分のはてなダイアリーとか、その他のブログでPython記事(略して「Py記事」)を書いちゃっている人は、グループ内の日記にコピペって頂くと、誰かが助かります。

fukuoka.pyのはてなグループ

らしいので、本家ブログ記事を↓に完璧コピペ。ついでに、他のPy記事についてのリンクも。(→Python

誰かが助かるといいなぁw


多分10日ほどで読了。とは言っても一通り目を通したってだけで、これから実際に触っていくに従って疑問点も出てくるのでしょうが。

みんなのPython

みんなのPython


↑の本には詳しく述べられていなかったことの補足で、下記サイトを。

Page not found · GitHub Pages
コーディング規約。Pythonに限った話ではないところも多い。
404 Not Found
ユニットテスト。みんなのPythonではdoctestが紹介されていたけど、ある程度網羅的なテストをやるならこっちかな。
404 Not Found
カバレッジ測定。PyDevにコマンドがあるのはすぐに分かったけど、使い方が分かりませんでした。リンク元の人も触れているけど、結果がエラーとして扱われるのがちょっとやだな…

まだPythonデビューしてちょっとだけど、コーディングしてて何か小気味いい感じ。(SIer的な)業務でやるならJavaとかの方が無難だろうけど、自分一人とか少数精鋭ならLLだと生産性が上がりそう。

あとは、PyDev on Eclipseがちょっと重いのでそれさえ何とかなれば。ま、次のマシンに換えたら大丈夫でしょう。

fukuoka.py参加

00:14 | fukuoka.py参加 - ikikko.py を含むブックマーク はてなブックマーク - fukuoka.py参加 - ikikko.py fukuoka.py参加 - ikikko.py のブックマークコメント

fukuoka.pyに参加しました。何で福岡って?それは、大学時代福岡で過ごしていい町だったし、何かしらつながりを持っておきたかった、それだけです。

こっちではPython関連のことを書いて、本家ブログではそれ以外を書こうかな。tracのように両方関わるやつは、両方コピーするかも。

福岡とかに住んでいなくてもOKですが、参加された方は、そのうち福岡に住んでください。

fukuoka.pyのはてなグループ

とりあえず今週末帰省する予定なので、4日だけ福岡に住みますw

m-hashimotom-hashimoto2008/11/18 10:34「PEP 8 -- Style Guide for Python Code」の和訳ってあったんですね!助かりました(笑。

ikikkoikikko2008/11/18 22:05さっそく助かったみたいで、光栄ですw
なるべく勉強記録を残していこうと思うので、
これからヨロシクです♪