示例#1
0
文件: genshi.py 项目: stpierre/dmr
    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
文件: data.py 项目: stpierre/dmr
    def parse(cls, node, employer=None):  # pylint: disable=W0221
        """
        :param node: The node to parse a job from
        :type node: docutils.nodes.Node
        :param employer: Optionally, the employer for this job, if it was
                         provided elsewhere and the job node only
                         describes a position at the employer.
        :type employer: dmr.data.Contact
        :returns: :class:`dmr.data.Job`
        """
        if employer is None:
            employer = Contact.parse(node)
            position = None
            logger.debug("Parsing job at %s" % employer.name)
        else:
            position = get_title(node)
            logger.debug("Parsing job %s at %s" % (position, employer))

        dates = Dates(None, None)
        datenode = child_by_class(node, docutils.nodes.paragraph)
        if datenode:
            dates = Dates.parse(datenode)

        job = cls(position=position, employer=employer, dates=dates)
        for item in child_by_class(node, docutils.nodes.bullet_list).children:
            if isinstance(item, docutils.nodes.comment):
                continue
            job.append(child_by_class(item, docutils.nodes.paragraph))
        return job
示例#3
0
文件: input.py 项目: stpierre/dmr
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
示例#4
0
文件: data.py 项目: stpierre/dmr
    def parse(cls, node):
        """ Parse a node into a :class:`dmr.data.Contact` object.  The
        node must either a) be a :class:`docutils.nodes.line_block`;
        or b) contain a :class:`docutils.nodes.Titular` and a
        :class:`docutils.nodes.line_block`.

        :param block: The line block to parse.
        :type block: docutils.nodes.Node
        :returns: :class:`dmr.data.Contact`
        """
        if isinstance(node, docutils.nodes.line_block):
            block = node
            name = None
        else:
            name = get_title(node)
            logger.debug("Parsing address block for %s" % name)
            block = child_by_class(node, docutils.nodes.line_block)
            if block is None:
                return cls(name, [], [], [], [], [])

        in_address = True
        address = []
        phone = []
        email = []
        url = []
        other = []
        for rawline in block.children:
            if isinstance(rawline, docutils.nodes.comment):
                continue
            line = _contain(rawline)
            ref = child_by_class(rawline, docutils.nodes.reference)
            if not name:
                name = line
                logger.debug("Parsing address block for %s" % name)
            elif ref:
                # email address, phone number, or url
                if ref.attributes['refuri'].startswith("mailto:"):
                    email.append(line)
                elif ref.attributes['refuri'].startswith("tel:"):
                    phone.append(line)
                else:
                    url.append(line)
                if in_address and address:
                    in_address = False
            elif cls.phone_re.match(line.astext()):
                phone.append(line)
                if in_address and address:
                    in_address = False
            elif in_address:
                address.append(line)
            else:
                other.append(line)
        return cls(name, address, phone, email, url, other)
示例#5
0
文件: data.py 项目: stpierre/dmr
    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
示例#6
0
文件: data.py 项目: stpierre/dmr
    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