Package logilab :: Package common :: Package ureports

[frames] | no frames]

# Source Code for Package logilab.common.ureports

      1  # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
      2  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
      3  #
      4  # This file is part of logilab-common.
      5  #
      6  # logilab-common is free software: you can redistribute it and/or modify it under
      7  # the terms of the GNU Lesser General Public License as published by the Free
      8  # Software Foundation, either version 2.1 of the License, or (at your option) any
      9  # later version.
     10  #
     11  # logilab-common 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 Lesser General Public License for more
     14  # details.
     15  #
     16  # You should have received a copy of the GNU Lesser General Public License along
     17  # with logilab-common.  If not, see <http://www.gnu.org/licenses/>.
     18  """Universal report objects and some formatting drivers.
     19
     20  A way to create simple reports using python objects, primarily designed to be
     21  formatted as text and html.
     22  """
     23  __docformat__ = "restructuredtext en"
     24
     25  import sys
     26
     27  from logilab.common.compat import StringIO
     28  from logilab.common.textutils import linesep
     29
     30
     31 -def get_nodes(node, klass):
     32      """return an iterator on all children node of the given klass"""
     33      for child in node.children:
     34          if isinstance(child, klass):
     35              yield child
     36          # recurse (FIXME: recursion controled by an option)
     37          for grandchild in get_nodes(child, klass):
     38              yield grandchild
     39
     40 -def layout_title(layout):
     41      """try to return the layout's title as string, return None if not found
     42      """
     43      for child in layout.children:
     44          if isinstance(child, Title):
     45              return u' '.join([node.data for node in get_nodes(child, Text)])
     46
     47 -def build_summary(layout, level=1):
     48      """make a summary for the report, including X level"""
     49      assert level > 0
     50      level -= 1
     51      summary = List(klass=u'summary')
     52      for child in layout.children:
     53          if not isinstance(child, Section):
     54              continue
     55          label = layout_title(child)
     56          if not label and not child.id:
     57              continue
     58          if not child.id:
     59              child.id = label.replace(' ', '-')
     60          node = Link(u'#'+child.id, label=label or child.id)
     61          # FIXME: Three following lines produce not very compliant
     62          # docbook: there are some useless <para><para>. They might be
     63          # replaced by the three commented lines but this then produces
     64          # a bug in html display...
     65          if level and [n for n in child.children if isinstance(n, Section)]:
     66              node = Paragraph([node, build_summary(child, level)])
     67          summary.append(node)
     68  #         summary.append(node)
     69  #         if level and [n for n in child.children if isinstance(n, Section)]:
     70  #             summary.append(build_summary(child, level))
     71      return summary
     72
     73
     74 -class BaseWriter(object):
     75      """base class for ureport writers"""
     76
     77 -    def format(self, layout, stream=None, encoding=None):
     78          """format and write the given layout into the stream object
     79
     80          unicode policy: unicode strings may be found in the layout;
     81          try to call stream.write with it, but give it back encoded using
     82          the given encoding if it fails
     83          """
     84          if stream is None:
     85              stream = sys.stdout
     86          if not encoding:
     87              encoding = getattr(stream, 'encoding', 'UTF-8')
     88          self.encoding = encoding or 'UTF-8'
     89          self.__compute_funcs = []
     90          self.out = stream
     91          self.begin_format(layout)
     92          layout.accept(self)
     93          self.end_format(layout)
     94
     95 -    def format_children(self, layout):
     96          """recurse on the layout children and call their accept method
     97          (see the Visitor pattern)
     98          """
     99          for child in getattr(layout, 'children', ()):
    100              child.accept(self)
    101
    102 -    def writeln(self, string=u''):
    103          """write a line in the output buffer"""
    104          self.write(string + linesep)
    105
    106 -    def write(self, string):
    107          """write a string in the output buffer"""
    108          try:
    109              self.out.write(string)
    110          except UnicodeEncodeError:
    111              self.out.write(string.encode(self.encoding))
    112
    113 -    def begin_format(self, layout):
    114          """begin to format a layout"""
    115          self.section = 0
    116
    117 -    def end_format(self, layout):
    118          """finished to format a layout"""
    119
    120 -    def get_table_content(self, table):
    121          """trick to get table content without actually writing it
    122
    123          return an aligned list of lists containing table cells values as string
    124          """
    125          result = [[]]
    126          cols = table.cols
    127          for cell in self.compute_content(table):
    128              if cols == 0:
    129                  result.append([])
    130                  cols = table.cols
    131              cols -= 1
    132              result[-1].append(cell)
    133          # fill missing cells
    134          while len(result[-1]) < cols:
    135              result[-1].append(u'')
    136          return result
    137
    138 -    def compute_content(self, layout):
    139          """trick to compute the formatting of children layout before actually
    140          writing it
    141
    142          return an iterator on strings (one for each child element)
    143          """
    144          # use cells !
    145          def write(data):
    146              try:
    147                  stream.write(data)
    148              except UnicodeEncodeError:
    149                  stream.write(data.encode(self.encoding))
    150          def writeln(data=u''):
    151              try:
    152                  stream.write(data+linesep)
    153              except UnicodeEncodeError:
    154                  stream.write(data.encode(self.encoding)+linesep)
    155          self.write = write
    156          self.writeln = writeln
    157          self.__compute_funcs.append((write, writeln))
    158          for child in layout.children:
    159              stream = StringIO()
    160              child.accept(self)
    161              yield stream.getvalue()
    162          self.__compute_funcs.pop()
    163          try:
    164              self.write, self.writeln = self.__compute_funcs[-1]
    165          except IndexError:
    166              del self.write
    167              del self.writeln
    168
    169
    170  from logilab.common.ureports.nodes import *
    171  from logilab.common.ureports.text_writer import TextWriter
    172  from logilab.common.ureports.html_writer import HTMLWriter
    173