PollyReports Additional Bands

I’ve added a new feature to the 1.7.6 version of PollyReports: additionalbands.  A Band instance may have one or more additionalbands defined (as a list of Band instances), and each will be rendered in order after the parent band renders.

Conceptually, this is much like the existing childbands feature; however, childbands become “part” of the parent band, rendering on the same page (and potentially forcing a page break before the parent band).  additionalbands are separate from the parent band, and from each other.

I added the feature to deal with a report that needed a two page long report footer.  So that’s what it’s for.

additionalbands render as part of the detailband, in groupheaders and groupfooters, and in the reportfooter.  They are not rendered as part of a pageheader or pagefooter band.  Also note that additionalbands will render childbands of their own.

Remember, you can get PollyReports using pip or by cloning the Github repo at:

http://github.com/Solomoriah/PollyReports

18 thoughts on PollyReports Additional Bands

  1. Hi, I am currently using your tutorials. When creating a page header the labels always come with a b in front of them. For example if the header is “Page Header” it gets printed as b’Page Header’. Why is this happening and whats the solution?

  2. The notation b’Page Header’ indicates a byte string, which is the kind of string Python 2 uses by default (and thus does not usually print in the b’xxx’ format). Reportlab likes Unicode; I’m guessing either you are using Python 3 or some version of Reportlab that is offended by byte strings.

    Take a look at this:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    chrisg@office:~$ python3
    Python 3.2.3 (default, Feb 27 2014, 21:33:50)
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> x = b"Heading"
    >>> x
    b'Heading'
    >>> str(x)
    b'Heading'
    >>> x.decode()
    'Heading'

    As you can see, to get Python 3 to accept the byte string as a string I have to use the decode method. You could use the format parameter of the Element class to do this, i.e.

    1
    Element(... format = lambda x: x.decode(), ...)

    If you are using Python 2, the code would be a little different, but you are still just converting the string to unicode. It appears that the unicode() constructor should do the trick if your page header text is strictly 7 bit ASCII:

    1
    Element(... format = lambda x: unicode(x), ...)

    or even:

    1
    Element(... format = unicode, ...)

    Try it out and let me know if you need further assistance.

  3. Thank you for your solution! I use Python 3 and It works!

    • You’re welcome, Frank! Glad it works for you. I get so little feedback on PollyReports that I’m not even sure if anyone else uses it besides me. But then, it was me I wrote it for…

      • I use it! Only on one project for now, but its a great tool to have around. Landed here looking a way to keep groups on a page.

        • Ooh, tough one. Polly isn’t really designed to work that way. Glad you’re liking it otherwise.

  4. I have been using PollyReports for a number of projects!

    I have two questions: Can I have two different detail bands (or two headers, or two footers) in a single report? Can I render the report twice on a single PDF, one below the other?

    Thanks! I love using your tool.

  5. Polly doesn’t support multiple detail bands (I’m assuming you mean switching between them somehow), nor multiple of other types of bands. If you aren’t talking about switching between them, but rather rendering one after another each time, you either want additionalbands or childbands (depending on whether you want them to stay together or not).

    As to the “rendering twice” question, yes, you can generate twice into the same Reportlab canvas, but note that the two instances of the report won’t be on the same page together anywhere… the end of the report includes a page eject, so the second report will begin on a new page. Also, if you want consistent page numbering you’ll have to “jimmy” the code for that (but it’s doable).

  6. How do I make my elements (primarily images) stop being cut in half by pagebreaks? I have a report header containing some basic info, covering half of the first page. The groupheaders start thereafter, but the images on the first page are cut in half. On page 2 and onward, they are formatted OK. I want to make sure nothing else but the reportheader is printed on page 1 . Regards

    • newpagebefore or newpageafter does not seem to work.
      The groupheaders attribute is a lsist of Band objects..

    • If you only want the reportheader on the first page, make it large enough that the next band won’t fit at all. To do this, add an Element that is very close to the bottom of the page with a value of ” ” (a string of one space).

      Not sure why your images are getting cut off. If you can post an example, I might be able to figure it out.

      • And I don’t know why I didnt figure that out sooner. In the end, I did what you suggested and that worked:

        pdf_ims = [Band([Element((0,0), (‘Helvetica’, 9), text=””)], newpageafter=1)] #Pagebreak
        # .. Append every other band to pdf_ims

        rpt.groupheaders = pdf_ims

        Worked for me.

        Is there a way to get the total number of pages in the document in the page header? It seems the onrender method generates the current length of the document. .

        • AFAI Can see from the source file, newpage is the only method who manipulates pagecount, which in turn is only called on generate, meaning I have to generate the PDF twice just to get the amount of pages?

        • The total number of pages is not available at the start of the report, as you have surmised, so no, you can’t put that number in the header without literally generating the report twice. Doesn’t seem worth it.

  7. For posterity, here’s what I did:

    def on_report(foo, bar, actual_pagenum=1):


    … # Generate pageheader with actual_pagenum

    if actual_pagenum == 1:
    actual_pagenum = rpt.__dict__[‘pagenumber’]
    on_report(foo, bar, actual_pagenum)
    else:
    canvas.save()
    Popen(‘thepdf.pdf’, shell=True)

    /Probably not/ worth it as you pointed out. However, I won’t be generating more than 1 at a time, which for makes it “ok” .

  8. Is there a way to get the detail band to stretch to accept multiline data? The data I get from my database is not a standard size. Some of the detail bands will need to expand to accommodate 1,2 or even 3 rows.

    • An Element value with newlines “\n” in it will print on multiple lines, broken wherever the newline appears. My solution involves creating a format function to word wrap the value; if you use a fixed-width font, it works great.

      There is a guy on Github with a modified PollyReports that uses a Reportlab function for wordwrapping, but I chose not to add his revisions because they add an explicit dependency I didn’t want.

      • Since Python comes with a wordwrap module, I decided to take advantage of that instead of writing a custom function.

        In my data, MSG-TEXT can be anywhere from 50-2000+ chars, so the following with a width of 80 works well for my report.

        import textwrap
        rowDict[“MSG-TEXT”] = textwrap.fill(rowDict[“MSG-TEXT”],80)

        The dictionary is then appended to the list of data rows I pass to PollyReports.

        Thanks for the help and the wrapper on Reportlab

Leave a Reply

Your email address will not be published. Required fields are marked *