読者です 読者をやめる 読者になる 読者になる

Tracのチケット一覧のCSV/TSVエクスポート

Tracでは、チケットの一覧を、CSV/TSV形式でエクスポートすることが可能です。
ただ、この出力は、以下のような問題があって多少使いづらい。

  • 文字コードUTF-8
  • 日付が一加工を加える必要がある形式
    • Trac0.11では秒をint値として出力したもの
    • Trac0.11で「2008-08-30T10:00:00Z+0900」というISO 8601形式


国際化としては正しいと思うのですが、これでは、出力したものをExcelで読み込んでグラフ表示したりする際にも、一手間かかってしまいまいます。


ということで、この問題を解決するべく、以下のようなパッチを作ってみました。
Trac0.10とTrac0.11では、処理が大分異なっているようなので、それぞれのパッチを作成しました。

  • 変更点
    • 文字コードをcp932とする
    • 日付の値はExcelの書式設定で言うところの「yyyy/mm/dd hh:mm:ss」という形式にする

Trac0.10

TracLightning 1.8.2を利用して確認しました。

  • 変更ファイル:\python-lib\trac\trac\ticket\report.py
    • 上記ファイルを「\python\Lib\site-packages\trac\ticket」配下にコピーし、apacheを再起動すると反映されます。


Index: report.py
===================================================================
--- report.py	(revision 1)
+++ report.py	(working copy)
@@ -491,11 +491,34 @@
     def _render_csv(self, req, cols, rows, sep=',', mimetype='text/plain',
                     filename=None):
         req.send_response(200)
-        req.send_header('Content-Type', mimetype + ';charset=utf-8')
+        req.send_header('Content-Type', mimetype + ';charset=cp932')
         if filename:
             req.send_header('Content-Disposition', 'filename=' + filename)
         req.end_headers()
 
+        def fmt_time(t):
+            return format_time(t)
+
+        def fmt_datetime(dt):
+            return format_datetime(dt)
+
+        col_conversions = {
+            'time'       : fmt_time,
+            'datetime'   : fmt_datetime,
+            'changetime' : fmt_datetime,
+            'date'       : fmt_datetime,
+            'created'    : fmt_datetime,
+            'modified'   : fmt_datetime,
+        }
+
+        converters = [col_conversions.get(c.strip('_'), unicode) for c in cols]
+
+        for rowindex in xrange(len(rows)):
+            row = list(rows[rowindex])
+            for colindex in xrange(len(row)):
+                row[colindex] = converters[colindex](row[colindex]).encode('utf-8')
+            rows[rowindex] = row
+
         req.write(sep.join(cols) + '\r\n')
         for row in rows:
             req.write(sep.join(

Trac0.11

TracLightning 2.0.6を利用して確認しました。

  • 変更ファイル:\python-lib\trac\trac\ticket\report.py
    • 上記ファイルを「\python\Lib\site-packages\Trac-0.11.1.ja1-py2.5.egg\trac\ticket」配下にコピーし、apacheを再起動すると反映されます。


Index: report.py
===================================================================
--- report.py	(revision 1)
+++ report.py	(working copy)
@@ -639,34 +639,34 @@
     def _send_csv(self, req, cols, rows, sep=',', mimetype='text/plain',
                   filename=None):
         req.send_response(200)
-        req.send_header('Content-Type', mimetype + ';charset=utf-8')
+        req.send_header('Content-Type', mimetype + ';charset=cp932')
         if filename:
             req.send_header('Content-Disposition', 'filename=' + filename)
         req.end_headers()
 
-        def iso_time(t):
-            return format_time(t, 'iso8601')
+        def fmt_time(t):
+            return format_time(t)
 
-        def iso_datetime(dt):
-            return format_datetime(dt, 'iso8601')
+        def fmt_datetime(dt):
+            return format_datetime(dt)
 
         col_conversions = {
-            'time': iso_time,
-            'datetime': iso_datetime,
-            'changetime': iso_datetime,
-            'date': iso_datetime,
-            'created': iso_datetime,
-            'modified': iso_datetime,
+            'time'       : fmt_time,
+            'datetime'   : fmt_datetime,
+            'changetime' : fmt_datetime,
+            'date'       : fmt_datetime,
+            'created'    : fmt_datetime,
+            'modified'   : fmt_datetime,
         }
 
         converters = [col_conversions.get(c.strip('_'), unicode) for c in cols]
 
         writer = csv.writer(req, delimiter=sep)
-        writer.writerow([unicode(c).encode('utf-8') for c in cols])
+        writer.writerow([unicode(c).encode('cp932') for c in cols])
         for row in rows:
             row = list(row)
             for i in xrange(len(row)):
-                row[i] = converters[i](row[i]).encode('utf-8')
+                row[i] = converters[i](row[i]).encode('cp932')
             writer.writerow(row)
 
         raise RequestDone



チケットの一覧だけでなく、チケット単体でもCSV/TSVエクスポートが可能なのですが、その場合は、web_ui.pyを修正することが必要となります。