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')
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
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
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)
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
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