def createPdf(self, text=None,
                  source_path=None,
                  output=None,
                  doctree=None,
                  compressed=False,
                  # This adds entries to the PDF TOC
                  # matching the rst source lines
                  debugLinesPdf=False):
        self.decoration = {'header': self.header,
                           'footer': self.footer,
                           'endnotes': [],
                           'extraflowables': []}

        self.pending_targets=[]
        self.targets=[]

        self.debugLinesPdf = debugLinesPdf

        if doctree is None:
            if text is not None:
                if self.language:
                    settings_overrides={'language_code': self.docutils_language}
                else:
                    settings_overrides={}
                settings_overrides['strip_elements_with_classes']=self.strip_elements_with_classes
                self.doctree = docutils.core.publish_doctree(text,
                    source_path=source_path,
                    settings_overrides=settings_overrides)
                #import pdb; pdb.set_trace()
                log.debug(self.doctree)
            else:
                log.error('Error: createPdf needs a text or a doctree')
                return
        else:
            self.doctree = doctree
            
        if self.numbered_links:
            # Transform all links to sections so they show numbers
            from sectnumlinks import SectNumFolder, SectRefExpander
            snf = SectNumFolder(self.doctree)
            self.doctree.walk(snf)
            srf = SectRefExpander(self.doctree, snf.sectnums)
            self.doctree.walk(srf)
        if self.strip_elements_with_classes:
            from docutils.transforms.universal import StripClassesAndElements
            sce = StripClassesAndElements(self.doctree)
            sce.apply()
            
        elements = self.gen_elements(self.doctree)

        # Find cover template, save it in cover_file
        def find_cover(name):
            cover_path=[self.basedir, os.path.expanduser('~/.rst2pdf'),
                os.path.join(self.PATH,'templates')]
            cover_file=None
            for d in cover_path:
                if os.path.exists(os.path.join(d,name)):
                    cover_file=os.path.join(d,name)
                    break
            return cover_file

        cover_file=find_cover(self.custom_cover)
        if cover_file is None:
            log.error("Can't find cover template %s, using default"%self.custom_cover)
            cover_file=find_cover('cover.tmpl')

        # Feed data to the template, get restructured text.
        cover_text = renderTemplate(tname=cover_file,
                            title=self.doc_title,
                            subtitle=self.doc_subtitle
                        )

        # This crashes sphinx because .. class:: in sphinx is
        # something else. Ergo, pdfbuilder does it in its own way.
        if not self.sphinx:

            elements = self.gen_elements(
                publish_secondary_doctree(cover_text, self.doctree, source_path)) + elements

        if self.blank_first_page:
            elements.insert(0,PageBreak())

        # Put the endnotes at the end ;-)
        endnotes = self.decoration['endnotes']
        if endnotes:
            elements.append(MySpacer(1, 2*cm))
            elements.append(Separation())
            for n in self.decoration['endnotes']:
                t_style = TableStyle(self.styles['endnote'].commands)
                colWidths = self.styles['endnote'].colWidths
                elements.append(DelayedTable([[n[0], n[1]]],
                    style=t_style, colWidths=colWidths))

        if self.floating_images:
            #from pudb import set_trace; set_trace()
            # Handle images with alignment more like in HTML
            new_elem=[]
            for i,e in enumerate(elements[::-1]):
                if (isinstance (e, MyImage) and e.image.hAlign != 'CENTER'
                        and new_elem):
                    # This is an image where flowables should wrap
                    # around it
                    popped=new_elem.pop()
                    new_elem.append(ImageAndFlowables(e,popped,
                        imageSide=e.image.hAlign.lower()))
                else:
                    new_elem.append(e)

            elements = new_elem
            elements.reverse()

        head = self.decoration['header']
        foot = self.decoration['footer']

        # So, now, create the FancyPage with the right sizes and elements
        FP = FancyPage("fancypage", head, foot, self)

        def cleantags(s):
            re.sub(r'<[^>]*?>', '',
                unicode(s).strip())

        pdfdoc = FancyDocTemplate(
            output,
            pageTemplates=[FP],
            showBoundary=0,
            pagesize=self.styles.ps,
            title=self.doc_title_clean,
            author=self.doc_author,
            pageCompression=compressed)
        pdfdoc.client =self

        if getattr(self, 'mustMultiBuild', False):
            # Force a multibuild pass
            if not isinstance(elements[-1],UnhappyOnce):
                log.info ('Forcing second pass so Total pages work')
                elements.append(UnhappyOnce())
        while True:
            try:
                log.info("Starting build")
                # See if this *must* be multipass
                pdfdoc.multiBuild(elements)
                # Force a multibuild pass

                # FIXME: since mustMultiBuild is set by the
                # first pass in the case of ###Total###, then we
                # make a new forced two-pass build. This is broken.
                # conceptually.

                if getattr(self, 'mustMultiBuild', False):
                    # Force a multibuild pass
                    if not isinstance(elements[-1],UnhappyOnce):
                        log.info ('Forcing second pass so Total pages work')
                        elements.append(UnhappyOnce())
                        continue
                ## Rearrange footnotes if needed
                if self.real_footnotes:
                    newStory=[]
                    fnPile=[]
                    for e in elements:
                        if getattr(e,'isFootnote',False):
                            # Add it to the pile
                            #if not isinstance (e, MySpacer):
                            fnPile.append(e)
                        elif getattr(e, '_atTop', False) or isinstance(
                                e, (UnhappyOnce, MyPageBreak)):
                            if fnPile:
                                fnPile.insert(0, Separation())
                                newStory.append(Sinker(fnPile))
                            newStory.append(e)
                            fnPile=[]
                        else:
                            newStory.append(e)
                    elements = newStory+fnPile
                    for e in elements:
                        if hasattr(e, '_postponed'):
                            delattr(e,'_postponed')
                    self.real_footnotes = False
                    continue



                break
            except ValueError, v:
                # FIXME: cross-document links come through here, which means
                # an extra pass per cross-document reference. Which sucks.
                #if v.args and str(v.args[0]).startswith('format not resolved'):
                    #missing=str(v.args[0]).split(' ')[-1]
                    #log.error('Adding missing reference to %s and rebuilding. This is slow!'%missing)
                    #elements.append(Reference(missing))
                    #for e in elements:
                        #if hasattr(e,'_postponed'):
                            #delattr(e,'_postponed')
                #else:
                    #raise
                raise

        #doc = SimpleDocTemplate("phello.pdf")
        #doc.build(elements)
        for fn in self.to_unlink:
            try:
                os.unlink(fn)
            except OSError:
                pass
Create a PDF from text (ReST input),
dataset/ETHPy150Open rst2pdf/rst2pdf/rst2pdf/createpdf.py/RstToPdf.createPdf