1. Olemis Lang
  2. trac-gviz

Commits

Olemis Lang  committed dfdb6b2

Added GViz provider to convert contents of attachments.

  • Participants
  • Parent commits 2ba1b6f
  • Branches providers

Comments (0)

Files changed (6)

File trac-dev/gviz/TODO

View file
  • Ignore whitespace
 
 X Implement CSV and TSV encoders by using `csv` module.
 
-+ Include helper to convert CSV attachments to GViz API JSON format.
-
-+ Integrate `IGVizTableEncoder` with MIME view.
-
-+ Implement indirect MIME conversions using GViz data tables.
+X Include helper to convert CSV attachments to GViz API JSON format.
 
 ~ Write tests for data sources included in TracGViz 1.3.4 that are 
   not about version control.
 
 + Provide `dutest` as an external dependency.
 
+- Integrate `IGVizTableEncoder` with MIME view.
+
+- Implement indirect MIME conversions using GViz data tables.
+
 - Include helper to convert CSV files under version control to GViz 
   API JSON format.
 

File trac-dev/gviz/tracgviz/__init__.py

View file
  • Ignore whitespace
     from timeline import *
     from vcs import *
     from xsv import GvizXSVConverter
+    from attachment import *
 #    from ig import *
     msg = 'Ok'
 except Exception, exc:

File trac-dev/gviz/tracgviz/attachment.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+# Copyright 2009-2011 Olemis Lang <olemis at gmail.com>
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+r"""Use contents of attachments to feed GViz data tables.
+
+Copyright 2009-2011 Olemis Lang <olemis at gmail.com>
+Licensed under the Apache License, Version 2.0 
+"""
+__author__ = 'Olemis Lang'
+
+from trac.core import Component, implements
+from trac.attachment import Attachment
+from trac.mimeview.api import Mimeview
+
+from api import gviz_col, gviz_param, IGVizDataProvider, GVizBadRequestError
+from util import UTF8Recoder
+
+from itertools import chain, count
+
+__all__ = 'GVizAttachmentProvider',
+
+class GVizAttachmentProvider(Component):
+    r"""Use the contents of attachments in order to feed GViz data 
+    tables.
+    """
+    implements(IGVizDataProvider)
+    
+    # IGVizDataProvider methods
+    def get_data_schema(self, req):
+        r"""Provide the schema used to populate GViz data tables out 
+        of the Python object containing the table contents.
+        
+        @req    (since version 1.3.3) an optional argument that can 
+                be used by data providers offering data in different 
+                ways depending upon the values provided at run-time 
+                for some parameters. If this function has more than 
+                a single argument then it *MUST* be the request 
+                being processed.
+        @return schema definition used to prepare the data table. See 
+                the documentation for `gviz_api.DataTable` class for 
+                more details about schemas.
+        """
+        try:
+          realm, parent, fnm = (req.args[x] for x in ('realm', 'id', 'name'))
+        except KeyError:
+          return GVizBadRequestError("Missing realm, resource ID or file name.")
+        a = Attachment(self.env, realm, parent, fnm)
+        req.perm(a.resource).require('ATTACHMENT_VIEW')
+        fd = a.open()
+        mimesys = Mimeview(self.env)
+        content = fd.read(mimesys.max_preview_size)
+        mimetype = mimesys.get_mimetype(fnm, content)
+        try :
+          fd.seek(0)                          # Back to the beginning
+        except :
+          content+= fd.read()
+        else :
+          content = UTF8Recoder(fd, mimesys.get_charset(content, mimetype))
+        (cols, data), mimetype, ext = mimesys.convert_content(
+                                                  req, mimetype, \
+                                                  content, 'trac.gviz')
+        req.args['rawdata'] = data
+        return cols
+    
+    @gviz_param('realm', "the realm of the resource owning the " \
+                          "attachment (i.e. a string like `'wiki'` " \
+                          "or `'ticket'`)")
+    @gviz_param('id', "an `id`, which uniquely identifies a resource " \
+                      "within its realm (e.g. wiki page name or ticket ID).")
+    @gviz_param('name', "the attachment file name.")
+    def get_data(self, req, tq, realm, id, name, **tqx):
+        r"""Retrieve attachment contents if possible (i.e. if there 
+        is a MIME converter available and able to transform the input 
+        content type into a GViz data table).
+        
+        The structure of the output data depends on the file contents, 
+        its MIME type, and other implementation details like the MIME 
+        converter in use.
+        """
+        val = req.args.get('rawdata') 
+        self.log.debug("IG: Returning data set %s", val)
+        return val or []
+    
+    def gviz_namespace(self):
+        return ('attachment', 'raw')
+
+

File trac-dev/gviz/tracgviz/gvizql.py

View file
  • Ignore whitespace
   sch = provider.get_data_schema.im_func.func_code
   sch_args = (sch.co_argcount > 1) and (req,) or ()
   if not tq:
+    sch = provider.get_data_schema(*sch_args)
     data = provider.get_data(req, None, **params)
-    return (provider.get_data_schema(*sch_args), data)
+    return (sch, data)
   else:
     tq = GVizQLParser().parse(tq)
     data = provider.get_data(req, tq, **params)

File trac-dev/gviz/tracgviz/util.py

View file
  • Ignore whitespace
           'get_column_desc', 'TYPES_2_GVIZ', 'get_column_desc', \
           'rpc_opt_sigs', 'REQFIELDS_DESC', 'REQFIELDS_DEFAULTS', \
           'is_dyn_schema', 'compile_pattern', 'ObjectIntercept', \
-          'send_response', 'iter_table_data', 'StringIO'
+          'send_response', 'iter_table_data', 'StringIO', 'UTF8Recoder'
 
 from trac.core import Component, ExtensionPoint, implements, TracError
 from trac.config import Option
+from trac.util.text import to_utf8
 from trac.web.api import RequestDone, Request
 from trac.web.chrome import Chrome
 from trac.web.main import RequestDispatcher
   from cStringIO import StringIO
 except ImportError:
   from StringIO import StringIO
+
+def UTF8Recoder(f, encoding='utf-8'):
+  r"""Iterator that reads an encoded stream and reencodes the input 
+  to UTF-8.
+  """
+  from codecs import EncodedFile
+  return EncodedFile(f, 'utf-8', encoding)

File trac-dev/gviz/tracgviz/xsv.py

View file
  • Ignore whitespace
 __author__ = 'Olemis Lang'
 
 from trac.core import Component, implements
-from trac.mimeview.api import IContentConverter
+from trac.mimeview.api import IContentConverter, Mimeview
 from trac.util.translation import _
 
 from csv import writer, QUOTE_MINIMAL, reader
     def get_supported_conversions(self):
         yield ('csv2gviz', _('GViz Data Table (Comma-delimited Text)'), 
                 'gviz', 'text/csv', 'trac.gviz', 8)
-        yield ('tab2gviz', _('GViz Data Table (Tab-delimited Text)'), 
+        yield ('tsv2gviz', _('GViz Data Table (Tab-delimited Text)'), 
                 'gviz', 'text/tab-separated-values', 'trac.gviz', 8)
     
     def convert_content(self, req, mimetype, content, key):
+        if not hasattr(content, 'read'):
+          fo = StringIO(content)
+        else :
+          fo = content
         if key == 'csv2gviz':
             sep = ','
-        elif key == 'tab2gviz':
+        elif key == 'tsv2gviz':
             sep = '\t'
-        return self.load_data(req, content, sep)
+        return self.load_data(req, fo, sep)
 
-    def load_data(self, req, data, sep=','):
+    def load_data(self, req, content, sep=','):
         r"""Prepare data delimited by a special character to be loaded 
         into instances of `DataTable`. It is possible to customize the 
         transformation by specifying the parameters 
                       in the first input row and `data` is an iterator 
                       returning the rest of the values.
         """
-        content = StringIO(data)
         csv_args = dict([x[4:], v] for x, v in req.args.iteritems() \
                                     if x.startswith('csv_'))
         csv_args['delimiter'] = sep