root/relatorio/reporting.py @ 1:da857f61c615

Revision 1:da857f61c615, 4.5 kB (checked in by Nicolas Evrard <nicoe@…>, 5 years ago)

- renamed mimetypes to templates

Line 
1###############################################################################
2#
3# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
4# Reserved.
5#
6# This program is free software; you can redistribute it and/or modify it under
7# the terms of the GNU General Public License as published by the Free Software
8# Foundation; either version 2 of the License, or (at your option) any later
9# version.
10#
11# This program is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14# details.
15#
16# You should have received a copy of the GNU General Public License along with
17# this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19###############################################################################
20
21__revision__ = "$Id: reporting.py 2 2008-07-04 15:49:31Z nicoe $"
22__metaclass__ = type
23
24import os, sys
25import warnings
26from cStringIO import StringIO
27from genshi.template import MarkupTemplate, TextTemplate
28from genshi.template import TemplateLoader
29
30from templates.odt import Template as OOTemplate
31from templates.pdf import Template as PDFTemplate
32
33def _absolute(path):
34    "Compute the absolute path of path relative to the caller file"
35    if os.path.isabs(path):
36        return path
37    caller_fname = sys._getframe(2).f_globals['__file__']
38    dir = os.path.dirname(caller_fname)
39    return os.path.abspath(os.path.join(dir, path))
40
41def _guess_type(mime):
42    mime = mime.lower()
43    type, stype = mime.split('/', 1)
44    if type == 'application':
45        if 'opendocument' in stype:
46            return 'oo.org'
47        else:
48            return stype
49    elif type == 'text':
50        if stype in ('xml', 'html', 'xhtml'):
51            return 'markup'
52        else:
53            return 'text'
54
55
56class MIMETemplateLoader(TemplateLoader):
57    """This subclass of TemplateLoader use mimetypes to search and find
58    templates to load.
59    """
60
61    factories = {'pdf': PDFTemplate,
62                 'oo.org': OOTemplate,
63                 'text': TextTemplate,
64                 'markup': MarkupTemplate}
65
66    mime_func = [_guess_type]
67
68    def get_type(self, mime):
69        for func in reversed(self.mime_func):
70            t = func(mime)
71            if t is not None:
72                return t
73
74    def load(self, path, mime):
75        rtype = self.get_type(mime)
76        return super(MIMETemplateLoader, self).load(path,
77                                                    cls=self.factories[rtype])
78
79    @classmethod
80    def add_factory(cls, abbr_mimetype, template_factory, id_function=None):
81        """adds a template factory to the already known factories"""
82        if abbr_mimetype in cls.factories:
83            warnings.warn('You are overriding an already defined link.')
84        cls.factories[abbr_mimetype] = template_factory
85        if id_function is not None:
86            cls.mime_func.append(id_function)
87
88
89class Report:
90    """Report is a simple interface on top of a rendering template.
91    """
92   
93    def __init__(self, path, mimetype, factory, loader):
94        self.fpath = path
95        self.mimetype = mimetype
96        self.data_factory = factory
97        self.tmpl_loader = loader
98
99    def __call__(self, obj, **kwargs):
100        template = self.tmpl_loader.load(self.fpath, self.mimetype)
101        data = self.data_factory(obj, **kwargs)
102        return StringIO(str(template.generate(**data)))
103
104
105class DefaultFactory:
106
107    def __call__(self, obj, **kwargs):
108        data = {}
109        data['o'] = obj
110        data['args'] = kwargs
111        return data
112
113
114class ReportRepository:
115    """ReportRepository stores the report definition associated to objects.
116
117    The report are indexed in this object by the object class they are working
118    on and the name given to it by the user.
119    """
120   
121    def __init__(self, datafactory=DefaultFactory):
122        self.reports = {}
123        self.default_factory = datafactory
124        self.loader = MIMETemplateLoader(auto_reload=True)
125
126    def add_report(self, klass, mimetype, template_path, data_factory=None,
127                   report_name='default'):
128        if data_factory is None:
129            data_factory = self.default_factory
130        reports = self.reports.setdefault(klass, {})
131        report = Report(_absolute(template_path), mimetype, data_factory(),
132                        self.loader)
133        reports[report_name] = mimetype, report
134        reports.setdefault(mimetype, []).append((report_name, report))
Note: See TracBrowser for help on using the browser.