Пример #1
0
    def output(self):
        logger.debug("Rendering document")
        data = dict(document=self.document,
                    contact=self.document.contact.render(self.renderer),
                    sections=[],
                    footer=None)
        for section in self.document:
            logger.debug("Rendering section '%s'" % section.name)
            data['sections'].append(section.render(self.renderer))

        if config.footer:
            data['footer'] = self.renderer(config.footer)

        tmpl_paths = [config.template_path,
                      os.path.expanduser('~/.dmr/templates')]
        logger.debug("Loading templates from %s" % tmpl_paths)
        loader = genshi.template.TemplateLoader(tmpl_paths)
        logger.info("Loading template at %s" % config.template)
        tmpl = loader.load(config.template,
                           cls=genshi.template.NewTextTemplate)
        logger.debug("Generating template output stream")
        stream = tmpl.generate(**data).filter(removecomment)
        logger.debug("Rendering template")
        try:
            return stream.render('text', strip_whitespace=False)
        except TypeError:
            return stream.render('text')
Пример #2
0
def parse(filehandle):
    """ Parse a document read from the given filehandle into a
    :class:`dmr.data.Document` object.

    The document must contain:

    * A top-level title, the resume owner's name;
    * A :class:`docutils.nodes.line_block` containing contact
      information for the resume, to be parsed with
      :func:`dmr.data.Contact.parse`; and
    * Any number of subsections that conform to the restrictions of
      the various :class:`dmr.data.Section` subclasses.

    :param filehandle: The file-like object to parse the document from.
    :type filehandle: file
    :returns: :class:`dmr.data.Document`
    """
    parser = Parser()
    settings = OptionParser(components=(Parser,)).get_default_values()
    logger.info("Parsing document from %s" % filehandle.name)
    document = new_document(filehandle.name, settings)
    try:
        parser.parse(filehandle.read(), document)
    except IOError:
        fatal("Could not parse %s: %s" % (filehandle.name, sys.exc_info()[1]))

    top = None
    options = dict()
    for child in document.children:
        if isinstance(child, docutils.nodes.Structural):
            if top:
                fatal("Document must have exactly one top-level heading")
            top = child
        elif isinstance(child, docutils.nodes.comment):
            contents = child_by_class(child, docutils.nodes.Text)
            if contents and contents.startswith("options"):
                opts = contents.splitlines()
                try:
                    # see if this is a format-specific option block
                    ofmt = opts[0].split("=")[1]
                    logger.debug("Found document options for %s: %s" %
                                 (ofmt, opts[1:]))
                except IndexError:
                    ofmt = None
                    logger.debug("Found default document options: %s" %
                                 opts[1:])
                options[ofmt] = opts[1:]
        else:
            logger.info("Skipping unknown node %s" % child)

    for ofmt in [None, config.format]:
        if ofmt in options:
            parse_document_options(options[ofmt])

    doc = Document.parse(top)
    doc.source = document
    return doc
Пример #3
0
 def parse(cls, node):
     section = super(References, cls).parse(node)
     for item in node.children[1:]:
         if not isinstance(item, (docutils.nodes.line_block,
                                  docutils.nodes.comment)):
             logger.info("Skipping unknown node in %s section '%s': %s" %
                         (cls.type, section.name.astext(), item))
             continue
         section.append(Contact.parse(item))
     return section
Пример #4
0
 def parse(cls, node):
     # we first try splitting on a space-delimited dash or 'to',
     # since dates can themselves contain dashes.  if that fails,
     # we split on a non-space delimited dash, which could be
     # ambiguous.
     for regex in cls.regexes:
         try:
             return cls(*regex.split(node.astext(), maxsplit=1))
         except TypeError:
             pass
     logger.info("No valid date range could be determined from %s" %
                 node.astext())
     return cls(node.astext(), None)
Пример #5
0
    def parse(cls, node):
        section = super(Experience, cls).parse(node)
        logger.debug("Parsing %s node %s" % (cls.type, section.name))
        for employernode in node.children:
            if not isinstance(employernode, docutils.nodes.Structural):
                continue

            if exclude(employernode):
                logger.debug("Skipping excluded employer %s" %
                             get_title(employernode))
                continue

            # Two ways this could be structured:
            # * With just employer (e.g., an Education section, which
            #   might only list the schools attended, not "position")
            # * Nested sections for employer and position
            if employernode.first_child_matching_class(
                docutils.nodes.Structural) is not None:
                # nested sections
                address = Contact.parse(employernode)
                for jobnode in employernode.children:
                    if not isinstance(jobnode, docutils.nodes.Structural):
                        if not isinstance(jobnode, (docutils.nodes.line_block,
                                                    docutils.nodes.Titular,
                                                    docutils.nodes.comment)):
                            logger.info("Skipping unknown node %s in job node"
                                        % jobnode)
                        continue
                    if exclude(jobnode):
                        logger.debug("Skipping excluded job %s" %
                                     get_title(jobnode))
                        continue

                    job = Job.parse(jobnode, employer=address)
                    section.append(job)
            else:
                section.append(Job.parse(employernode))
        return section
Пример #6
0
    def parse(cls, node):
        doc = cls()
        doc.contact = Contact.parse(node)

        for data in node.children:
            if not isinstance(data, docutils.nodes.Structural):
                if not isinstance(data, (docutils.nodes.line_block,
                                         docutils.nodes.Titular,
                                         docutils.nodes.comment)):
                    logger.info("Skipping unknown node %s" % data)
                continue

            if exclude(data):
                logger.debug("Skipping excluded section %s" % get_title(data))
                continue

            for sectiontype in sections:
                if sectiontype.is_valid(data):
                    doc.append(sectiontype.parse(data))
                    break
            else:
                logger.info("Skipping unknown section %s" % get_title(data))
        return doc