Skip to content

ontodoc

A module for documenting ontologies.

attrdict

A dict with attribute access.

Note that methods like key() and update() may be overridden.

DocPP

Documentation pre-processor.

It supports the following features:

  • Comment lines

    %% Comment line...
    
  • Insert header with given level

    %HEADER label [level=1]
    
  • Insert figure with optional caption and width. filepath should be relative to basedir. If width is 0, no width will be specified.

    %FIGURE filepath [caption='' width=0px]
    
  • Include other markdown files. Header levels may be up or down with shift

    %INCLUDE filepath [shift=0]
    
  • Insert generated documentation for ontology entity. The header level may be set with header_level.

    %ENTITY name [header_level=3]
    
  • Insert generated documentation for ontology branch name. Options:

    • header_level: Header level.
    • terminated: Whether to branch should be terminated at all branch names in the final document.
    • include_leafs: Whether to include leaf.

      %BRANCH name [header_level=3 terminated=1 include_leafs=0 namespaces='' ontologies='']

  • Insert generated figure of ontology branch name. The figure is written to path. The default path is figdir/name, where figdir is given at class initiation. It is recommended to exclude the file extension from path. In this case, the default figformat will be used (and easily adjusted to the correct format required by the backend). leafs may be a comma- separated list of leaf node names.

    %BRANCHFIG name [path='' caption='' terminated=1 include_leafs=1
                     strict_leafs=1, width=0px leafs='' relations=all
                     edgelabels=0 namespaces='' ontologies='']
    
  • This is a combination of the %HEADER and %BRANCHFIG directives.

    %BRANCHHEAD name [level=2  path='' caption='' terminated=1
                      include_leafs=1 width=0px leafs='']
    
  • This is a combination of the %HEADER, %BRANCHFIG and %BRANCH directives. It inserts documentation of branch name, with a header followed by a figure and then documentation of each element.

    %BRANCHDOC name [level=2  path='' title='' caption='' terminated=1
                     strict_leafs=1 width=0px leafs='' relations='all'
                     rankdir='BT' legend=1 namespaces='' ontologies='']
    
  • Insert generated documentation for all entities of the given type. Valid values of type are: "classes", "individuals", "object_properties", "data_properties", "annotations_properties"

    %ALL type [header_level=3, namespaces='', ontologies='']
    
  • Insert generated figure of all entities of the given type. Valid values of type are: "classes", "object_properties" and "data_properties".

    %ALLFIG type
    

Parameters

template : str Input template. ontodoc : OntoDoc instance Instance of OntoDoc basedir : str Base directory for including relative file paths. figdir : str Default directory to store generated figures. figformat : str Default format for generated figures. figscale : float Default scaling of generated figures. maxwidth : float Maximum figure width. Figures larger than this will be rescaled. imported : bool Whether to include imported entities.

copy(self)

Returns a copy of self.

Source code in ontopy/ontodoc.py
def copy(self):
    """Returns a copy of self."""
    docpp = DocPP('', self.ontodoc, self.basedir, figformat=self.figformat,
                  figscale=self.figscale, maxwidth=self.maxwidth)
    docpp.lines[:] = self.lines
    docpp.figdir = self.figdir
    return docpp

get_branches(self)

Returns a list with all branch names as specified with %BRANCH (in current and all included documents). The returned value is cached for efficiency purposes and so that it is not lost after processing branches.

Source code in ontopy/ontodoc.py
def get_branches(self):
    """Returns a list with all branch names as specified with %BRANCH
    (in current and all included documents).  The returned value is
    cached for efficiency purposes and so that it is not lost after
    processing branches."""
    if self._branch_cache is None:
        names = []
        docpp = self.copy()
        docpp.process_includes()
        for line in docpp.lines:
            if line.startswith('%BRANCH'):
                names.append(shlex.split(line)[1])
        self._branch_cache = names
    return self._branch_cache

get_buffer(self)

Returns the current buffer.

Source code in ontopy/ontodoc.py
def get_buffer(self):
    """Returns the current buffer."""
    return '\n'.join(self.lines)

process(self)

Perform all pre-processing steps.

Source code in ontopy/ontodoc.py
def process(self):
    """Perform all pre-processing steps."""
    if not self._processed:
        self.process_comments()
        self.process_headers()
        self.process_figures()
        self.process_entities()
        self.process_branches()
        self.process_branchfigs()
        self.process_branchdocs()
        self.process_alls()
        self.process_allfig()
        self.process_includes()
        self._processed = True

process_allfig(self)

Process all %ALLFIG directives.

Source code in ontopy/ontodoc.py
def process_allfig(self):
    """Process all %ALLFIG directives."""
    onto = self.ontodoc.onto
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%ALLFIG '):
            tokens = shlex.split(line)
            type = tokens[1]
            opts = get_options(tokens[2:], path='', level=3, terminated=0,
                               include_leafs=1, strict_leafs=1, width=0,
                               leafs='', relations='isA', edgelabels=0,
                               rankdir='BT', legend=1,
                               namespaces='', ontologies='')
            if type == 'classes':
                roots = onto.get_root_classes(imported=self.imported)
            elif type in ('object_properties', 'relations'):
                roots = onto.get_root_object_properties(
                    imported=self.imported)
            elif type == 'data_properties':
                roots = onto.get_root_data_properties(
                    imported=self.imported)
            else:
                raise InvalidTemplateError(
                    'Invalid argument to %%ALLFIG: %s' % type)

            included_namespaces = opts.namespaces.split(
                ',') if opts.namespaces else ()
            included_ontologies = opts.ontologies.split(
                ',') if opts.ontologies else ()

            sec = []
            for root in roots:
                name = asstring(root)
                filepath, leafs, width = self._make_branchfig(
                    name, opts.path, opts.terminated, opts.include_leafs,
                    opts.strict_leafs, opts.width, opts.leafs,
                    opts.relations, opts.edgelabels, opts.rankdir,
                    opts.legend, included_namespaces, included_ontologies)
                title = 'Taxonomy of %s.' % name
                sec.append(
                    self.ontodoc.get_header(title, int(opts.level)))
                caption = 'Taxonomy of %s.' % name
                sec.extend(self.ontodoc.get_figure(
                    filepath, caption=caption, width=width).split('\n'))

            del self.lines[i]
            self.lines[i: i] = sec

process_alls(self)

Expand all %ALL specifications.

Source code in ontopy/ontodoc.py
def process_alls(self):
    """Expand all %ALL specifications."""
    onto = self.ontodoc.onto
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%ALL '):
            tokens = shlex.split(line)
            type = tokens[1]
            opts = get_options(tokens[2:], header_level=3)
            if type == 'classes':
                items = onto.classes(imported=self.imported)
            elif type in ('object_properties', 'relations'):
                items = onto.object_properties(imported=self.imported)
            elif type == 'data_properties':
                items = onto.data_properties(imported=self.imported)
            elif type == 'annotation_properties':
                items = onto.annotation_properties(imported=self.imported)
            elif type == 'individuals':
                items = onto.individuals(imported=self.imported)
            else:
                raise InvalidTemplateError(
                    'Invalid argument to %%ALL: %s' % type)
            items = sorted(items, key=lambda x: asstring(x))
            del self.lines[i]
            self.lines[i: i] = self.ontodoc.itemsdoc(
                items, int(opts.header_level)).split('\n')

process_branchdocs(self)

Process all %BRANCHDOC and %BRANCHEAD directives.

Source code in ontopy/ontodoc.py
def process_branchdocs(self):
    """Process all %BRANCHDOC and  %BRANCHEAD directives."""
    onto = self.ontodoc.onto
    for i, line in reversed(list(enumerate(self.lines))):
        if (line.startswith('%BRANCHDOC ') or
                line.startswith('%BRANCHHEAD ')):
            with_branch = True if line.startswith('%BRANCHDOC ') else False
            tokens = shlex.split(line)
            name = tokens[1]
            title = camelsplit(name)
            title = title[0].upper() + title[1:] + ' branch'
            opts = get_options(tokens[2:], level=2, path='', title=title,
                               caption=title + '.', terminated=1,
                               strict_leafs=1, width=0,
                               leafs='', relations='all', edgelabels=0,
                               rankdir='BT', legend=1,
                               namespaces='', ontologies='')

            included_namespaces = opts.namespaces.split(
                ',') if opts.namespaces else ()
            included_ontologies = opts.ontologies.split(
                ',') if opts.ontologies else ()

            include_leafs = 1
            filepath, leafs, width = self._make_branchfig(
                name, opts.path, opts.terminated, include_leafs,
                opts.strict_leafs, opts.width, opts.leafs, opts.relations,
                opts.edgelabels, opts.rankdir, opts.legend,
                included_namespaces, included_ontologies)

            sec = []
            sec.append(
                self.ontodoc.get_header(opts.title, int(opts.level)))
            sec.append(
                self.ontodoc.get_figure(filepath, caption=opts.caption,
                                        width=width))
            if with_branch:
                include_leafs = 0
                branch = filter_classes(
                    onto.get_branch(name, leafs, include_leafs),
                    included_namespaces=included_namespaces,
                    included_ontologies=included_ontologies)
                sec.append(
                    self.ontodoc.itemsdoc(branch, int(opts.level + 1)))

            del self.lines[i]
            self.lines[i: i] = sec

process_branches(self)

Expand all %BRANCH specifications.

Source code in ontopy/ontodoc.py
def process_branches(self):
    """Expand all %BRANCH specifications."""
    onto = self.ontodoc.onto

    # Get all branch names in final document
    names = self.get_branches()
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%BRANCH '):
            tokens = shlex.split(line)
            name = tokens[1]
            opts = get_options(tokens[2:], header_level=3, terminated=1,
                               include_leafs=0,
                               namespaces='', ontologies='')
            leafs = names if opts.terminated else ()

            included_namespaces = opts.namespaces.split(
                ',') if opts.namespaces else ()
            included_ontologies = opts.ontologies.split(
                ',') if opts.ontologies else ()

            branch = filter_classes(
                onto.get_branch(name, leafs, opts.include_leafs),
                included_namespaces=included_namespaces,
                included_ontologies=included_ontologies)

            del self.lines[i]
            self.lines[i: i] = self.ontodoc.itemsdoc(
                branch, int(opts.header_level)).split('\n')

process_branchfigs(self)

Process all %BRANCHFIG directives.

Source code in ontopy/ontodoc.py
def process_branchfigs(self):
    """Process all %BRANCHFIG directives."""
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%BRANCHFIG '):
            tokens = shlex.split(line)
            name = tokens[1]
            opts = get_options(
                tokens[2:], path='', caption='', terminated=1,
                include_leafs=1, strict_leafs=1, width=0, leafs='',
                relations='all', edgelabels=0, rankdir='BT', legend=1,
                namespaces='', ontologies='')

            included_namespaces = opts.namespaces.split(
                ',') if opts.namespaces else ()
            included_ontologies = opts.ontologies.split(
                ',') if opts.ontologies else ()

            filepath, leafs, width = self._make_branchfig(
                name, opts.path, opts.terminated, opts.include_leafs,
                opts.strict_leafs, opts.width, opts.leafs, opts.relations,
                opts.edgelabels, opts.rankdir, opts.legend,
                included_namespaces, included_ontologies)

            del self.lines[i]
            self.lines[i: i] = self.ontodoc.get_figure(
                filepath, caption=opts.caption, width=width).split('\n')

process_comments(self)

Strips out comment lines starting with "%%".

Source code in ontopy/ontodoc.py
def process_comments(self):
    """Strips out comment lines starting with "%%"."""
    self.lines = [line for line in self.lines if not line.startswith('%%')]

process_entities(self)

Expand all %ENTITY specifications.

Source code in ontopy/ontodoc.py
def process_entities(self):
    """Expand all %ENTITY specifications."""
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%ENTITY '):
            tokens = shlex.split(line)
            name = tokens[1]
            opts = get_options(tokens[2:], header_level=3)
            del self.lines[i]
            self.lines[i: i] = self.ontodoc.itemdoc(
                name, int(opts.header_level)).split('\n')

process_figures(self)

Expand all %FIGURE specifications.

Source code in ontopy/ontodoc.py
def process_figures(self):
    """Expand all %FIGURE specifications."""
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%FIGURE '):
            tokens = shlex.split(line)
            path = tokens[1]
            opts = get_options(tokens[2:], caption='', width=0)
            del self.lines[i]
            self.lines[i: i] = self.ontodoc.get_figure(
                os.path.join(self.basedir, path),
                caption=opts.caption, width=opts.width).split('\n')

process_headers(self)

Expand all %HEADER specifications.

Source code in ontopy/ontodoc.py
def process_headers(self):
    """Expand all %HEADER specifications."""
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%HEADER '):
            tokens = shlex.split(line)
            name = tokens[1]
            opts = get_options(tokens[2:], level=1)
            del self.lines[i]
            self.lines[i: i] = self.ontodoc.get_header(
                name, int(opts.level)).split('\n')

process_includes(self)

Process all %INCLUDE directives.

Source code in ontopy/ontodoc.py
def process_includes(self):
    """Process all %INCLUDE directives."""
    for i, line in reversed(list(enumerate(self.lines))):
        if line.startswith('%INCLUDE '):
            tokens = shlex.split(line)
            filepath = tokens[1]
            opts = get_options(tokens[2:], shift=0)
            with open(os.path.join(self.basedir, filepath), 'rt') as f:
                docpp = DocPP(
                    f.read(), self.ontodoc,
                    basedir=os.path.dirname(filepath),
                    figformat=self.figformat, figscale=self.figscale,
                    maxwidth=self.maxwidth)
                docpp.figdir = self.figdir
            if opts.shift:
                docpp.shift_header_levels(int(opts.shift))
            docpp.process()
            del self.lines[i]
            self.lines[i: i] = docpp.lines

shift_header_levels(self, shift)

Shift header level of all hashtag-headers in buffer. Underline headers are ignored.

Source code in ontopy/ontodoc.py
def shift_header_levels(self, shift):
    """Shift header level of all hashtag-headers in buffer.  Underline
    headers are ignored."""
    if not shift:
        return
    pat = re.compile('^#+ ')
    for i, line in enumerate(self.lines):
        m = pat.match(line)
        if m:
            if shift > 0:
                self.lines[i] = '#' * shift + line
            elif shift < 0:
                n = m.end()
                if shift > n:
                    self.lines[i] = line.lstrip('# ')
                else:
                    self.lines[i] = line[n:]

write(self, outfile, format=None, pandoc_option_files=(), pandoc_options=(), genfile=None, verbose=True)

Writes documentation to outfile.

Parameters

outfile : str File that the documentation is written to. format : str Output format. If it is "md" or "simple-html", the built-in template generator is used. Otherwise pandoc is used. If not given, the format is inferred from the outfile name extension. pandoc_option_files : sequence Sequence with command line arguments provided to pandoc. pandoc_options : sequence Additional pandoc options overriding options read from pandoc_option_files. genfile : str Store temporary generated markdown input file to pandoc to this file (for debugging). verbose : bool Whether to show some messages when running pandoc.

Source code in ontopy/ontodoc.py
def write(self, outfile, format=None, pandoc_option_files=(),
          pandoc_options=(), genfile=None, verbose=True):
    """Writes documentation to `outfile`.

    Parameters
    ----------
    outfile : str
        File that the documentation is written to.
    format : str
        Output format.  If it is "md" or "simple-html",
        the built-in template generator is used.  Otherwise
        pandoc is used.  If not given, the format is inferred
        from the `outfile` name extension.
    pandoc_option_files : sequence
        Sequence with command line arguments provided to pandoc.
    pandoc_options : sequence
        Additional pandoc options overriding options read from
    `pandoc_option_files`.
    genfile : str
        Store temporary generated markdown input file to pandoc
        to this file (for debugging).
    verbose : bool
        Whether to show some messages when running pandoc.
    """
    self.process()
    content = self.get_buffer()

    substitutions = self.ontodoc.style.get('substitutions', [])
    for reg, sub in substitutions:
        content = re.sub(reg, sub, content)

    format = get_format(outfile, format)
    if format not in ('simple-html', 'markdown', 'md'):  # Run pandoc
        if not genfile:
            f = NamedTemporaryFile(mode='w+t', suffix='.md')
            f.write(content)
            f.flush()
            genfile = f.name
        else:
            with open(genfile, 'wt') as f:
                f.write(content)
        run_pandoc(genfile, outfile, format,
                   pandoc_option_files=pandoc_option_files,
                   pandoc_options=pandoc_options,
                   verbose=verbose)
    else:
        if verbose:
            print('Writing:', outfile)
        with open(outfile, 'wt') as f:
            f.write(content)

InvalidTemplateError

Raised on errors in template files.

OntoDoc

A class for helping documentating ontologies.

Parameters

onto : Ontology instance The ontology that should be documented. style : dict | "html" | "markdown" | "markdown_tex" A dict defining the following template strings (and substitutions):

:header: Formats an header.
    Substitutions: {level}, {label}
:link: Formats a link.
   Substitutions: {name}
:point: Formats a point (list item).
   Substitutions: {point}, {ontology}
:points: Formats a list of points.  Used within annotations.
   Substitutions: {points}, {ontology}
:annotation: Formats an annotation.
    Substitutions: {key}, {value}, {ontology}
:substitutions: list of ``(regex, sub)`` pairs for substituting
    annotation values.

get_default_template(self)

Returns default template.

Source code in ontopy/ontodoc.py
def get_default_template(self):
    """Returns default template."""
    title = os.path.splitext(
        os.path.basename(self.onto.base_iri.rstrip('/#')))[0]
    irilink = self.style.get('link', '{name}').format(
        name=self.onto.base_iri, url=self.onto.base_iri,
        lowerurl=self.onto.base_iri)
    s = dedent('''\
    %HEADER {title}
    Documentation of {irilink}

    %HEADER Relations level=2
    %ALL object_properties

    %HEADER Classes level=2
    %ALL classes

    %HEADER Individuals level=2
    %ALL individuals

    %HEADER Appendix               level=1
    %HEADER "Relation taxonomies"  level=2
    %ALLFIG object_properties

    %HEADER "Class taxonomies"     level=2
    %ALLFIG classes
    ''').format(ontology=self.onto, title=title, irilink=irilink)
    return s

get_figure(self, path, caption='', width=None)

Returns a formatted insert-figure-directive.

Source code in ontopy/ontodoc.py
def get_figure(self, path, caption='', width=None):
    """Returns a formatted insert-figure-directive."""
    figwidth_style = self.style.get('figwidth', '')
    figure_style = self.style.get('figure', '')
    figwidth = figwidth_style.format(width=width) if width else ''
    return figure_style.format(path=path, caption=caption,
                               figwidth=figwidth)

get_header(self, label, header_level=1)

Returns label formatted as a header of given level.

Source code in ontopy/ontodoc.py
def get_header(self, label, header_level=1):
    """Returns `label` formatted as a header of given level."""
    header_style = self.style.get('header', '{label}\n')
    return header_style.format(
        '', level=header_level, label=label, lowerlabel=label.lower())

itemdoc(self, item, header_level=3, show_disjoints=False)

Returns documentation of item.

Parameters

item : obj | label The class, individual or relation to document. header_level : int Header level. Defaults to 3. show_disjoints : Bool Whether to show disjoint_with relations.

Source code in ontopy/ontodoc.py
def itemdoc(self, item, header_level=3, show_disjoints=False):
    """Returns documentation of `item`.

    Parameters
    ----------
    item : obj | label
        The class, individual or relation to document.
    header_level : int
        Header level. Defaults to 3.
    show_disjoints : Bool
        Whether to show `disjoint_with` relations.
    """
    onto = self.onto
    if isinstance(item, str):
        item = self.onto.get_by_label(item)

    header_style = self.style.get('header', '{label}\n')
    link_style = self.style.get('link', '{name}')
    point_style = self.style.get('point', '{point}')
    points_style = self.style.get('points', '{points}')
    annotation_style = self.style.get('annotation', '{key}: {value}\n')
    substitutions = self.style.get('substitutions', [])

    # Logical "sorting" of annotations
    order = dict(definition='00', axiom='01', theorem='02',
                 elucidation='03', domain='04', range='05', example='06')

    doc = []

    # Header
    label = get_label(item)
    doc.append(header_style.format(
        '', level=header_level, label=label, lowerlabel=label.lower()))

    # Add warning about missing prefLabel
    if not hasattr(item, 'prefLabel') or not item.prefLabel.first():
        doc.append(annotation_style.format(
            key='Warning', value='Missing prefLabel'))

    # Add iri
    doc.append(annotation_style.format(
        key='IRI', value=asstring(item.iri, link_style), ontology=onto))

    # Add annotations
    if isinstance(item, owlready2.Thing):
        annotations = item.get_individual_annotations()
    else:
        annotations = item.get_annotations()

    for key in sorted(annotations.keys(),
                      key=lambda key: order.get(key, key)):
        for value in annotations[key]:
            if self.url_regex.match(value):
                doc.append(annotation_style.format(
                    key=key, value=asstring(value, link_style)))
            else:
                for reg, sub in substitutions:
                    value = re.sub(reg, sub, value)
                doc.append(annotation_style.format(
                    key=key, value=value))

    # ...add relations from is_a
    points = []
    nonProp = (owlready2.ThingClass,  # owlready2.Restriction,
               owlready2.And, owlready2.Or, owlready2.Not)
    for p in item.is_a:
        if (isinstance(p, nonProp) or
            (isinstance(item, owlready2.PropertyClass) and
             isinstance(p, owlready2.PropertyClass))):
            points.append(point_style.format(
                point='is_a ' + asstring(p, link_style), ontology=onto))
        else:
            points.append(point_style.format(
                point=asstring(p, link_style), ontology=onto))

    # ...add equivalent_to relations
    for e in item.equivalent_to:
        points.append(point_style.format(
            point='equivalent_to ' + asstring(e, link_style)))

    # ...add disjoint_with relations
    if show_disjoints and hasattr(item, 'disjoint_with'):
        s = set(item.disjoint_with(reduce=True))
        points.append(point_style.format(
            point='disjoint_with ' + ', '.join(asstring(e, link_style)
                                               for e in s), ontology=onto))

    # ...add disjoint_unions
    if hasattr(item, 'disjoint_unions'):
        for u in item.disjoint_unions:
            s = ', '.join(asstring(e, link_style) for e in u)
            points.append(point_style.format(
                point='disjoint_union_of ' + s, ontology=onto))

    # ...add inverse_of relations
    if hasattr(item, 'inverse_property') and item.inverse_property:
        points.append(point_style.format(
            point='inverse_of ' + asstring(
                item.inverse_property, link_style)))

    # ...add domain restrictions
    for d in getattr(item, 'domain', ()):
        points.append(point_style.format(
            point='domain ' + asstring(d, link_style)))

    # ...add range restrictions
    for d in getattr(item, 'range', ()):
        points.append(point_style.format(
            point='range ' + asstring(d, link_style)))

    # Add points (from is_a)
    if points:
        value = points_style.format(
            points=''.join(points), ontology=onto)
        doc.append(annotation_style.format(
            key='Subclass of', value=value, ontology=onto))

    # Instances (individuals)
    if hasattr(item, 'instances'):
        points = []
        for e in [i for i in item.instances() if item in i.is_instance_of]:
            points.append(point_style.format(
                point=asstring(e, link_style), ontology=onto))
        if points:
            value = points_style.format(
                points=''.join(points), ontology=onto)
            doc.append(annotation_style.format(
                key='Individuals', value=value, ontology=onto))

    return '\n'.join(doc)

itemsdoc(self, items, header_level=3)

Returns documentation of items.

Source code in ontopy/ontodoc.py
def itemsdoc(self, items, header_level=3):
    """Returns documentation of `items`."""
    sep_style = self.style.get('sep', '\n')
    doc = []
    for item in items:
        doc.append(self.itemdoc(item, header_level))
        doc.append(sep_style.format(ontology=self.onto))
    return '\n'.join(doc)

append_pandoc_options(options, updates)

Append updates to pandoc options options.

Parameters

options : sequence Sequence with initial Pandoc options. updates : sequence of str Sequence of strings of the form "--longoption=value", where longoption is a valid pandoc long option and value is the new value. The "=value" part is optional.

Strings of the form "no-longoption" will filter out "--longoption"
from `options`.

Returns

new_options : list Updated pandoc options.

Source code in ontopy/ontodoc.py
def append_pandoc_options(options, updates):
    """Append `updates` to pandoc options `options`.

    Parameters
    ----------
    options : sequence
        Sequence with initial Pandoc options.
    updates : sequence of str
        Sequence of strings of the form "--longoption=value", where
        ``longoption`` is a valid pandoc long option and ``value`` is the
        new value.  The "=value" part is optional.

        Strings of the form "no-longoption" will filter out "--longoption"
        from `options`.

    Returns
    -------
    new_options : list
        Updated pandoc options.
    """
    # Valid pandoc options starting with "--no-XXX"
    no_options = set('no-highlight')

    if not updates:
        return list(options)

    u = {}
    for s in updates:
        k, sep, v = s.partition('=')
        u[k.lstrip('-')] = v if sep else None
        filter_out = set(k for k, v in u.items()
                         if k.startswith('no-') and k not in no_options)
        _filter_out = set('--' + k[3:] for k in filter_out)
        new_options = [opt for opt in options
                       if opt.partition('=')[0] not in _filter_out]
        new_options.extend(['--%s' % k if v is None else '--%s=%s' % (k, v)
                            for k, v in u.items()
                            if k not in filter_out])
    return new_options

get_docpp(ontodoc, infile, figdir='genfigs', figformat='png', maxwidth=None, imported=False)

Read infile and return a new docpp instance.

Source code in ontopy/ontodoc.py
def get_docpp(ontodoc, infile, figdir='genfigs', figformat='png',
              maxwidth=None, imported=False):
    """Read `infile` and return a new docpp instance."""
    if infile:
        with open(infile, 'rt') as f:
            template = f.read()
        basedir = os.path.dirname(infile)
    else:
        template = ontodoc.get_default_template()
        basedir = '.'

    docpp = DocPP(template, ontodoc, basedir=basedir, figdir=figdir,
                  figformat=figformat, maxwidth=maxwidth, imported=imported)

    return docpp

get_figformat(format)

Infer preferred figure format from output format.

Source code in ontopy/ontodoc.py
def get_figformat(format):
    """Infer preferred figure format from output format."""
    if format == 'pdf':
        figformat = 'pdf'  # XXX
    elif 'html' in format:
        figformat = 'svg'
    else:
        figformat = 'png'
    return figformat

get_format(outfile, format=None)

Infer format from outfile and format.

Source code in ontopy/ontodoc.py
def get_format(outfile, format=None):
    """Infer format from outfile and format."""
    if format is None:
        format = os.path.splitext(outfile)[1]
    if not format:
        format = 'html'
    if format.startswith('.'):
        format = format[1:]
    return format

get_maxwidth(format)

Infer preferred max figure width from output format.

Source code in ontopy/ontodoc.py
def get_maxwidth(format):
    """Infer preferred max figure width from output format."""
    if format == 'pdf':
        maxwidth = 668
    else:
        maxwidth = 1024
    return maxwidth

get_options(opts, **kw)

Returns a dict with options from the sequence opts with "name=value" pairs. Valid option names and default values are provided with the keyword arguments.

Source code in ontopy/ontodoc.py
def get_options(opts, **kw):
    """Returns a dict with options from the sequence `opts` with
    "name=value" pairs. Valid option names and default values are
    provided with the keyword arguments."""
    d = attrdict(kw)
    for opt in opts:
        if '=' not in opt:
            raise InvalidTemplateError('Missing "=" in template option: %r' %
                                       opt)
        name, value = opt.split('=', 1)
        if name not in d:
            raise InvalidTemplateError('Invalid template option: %r' % name)
        t = type(d[name])
        d[name] = t(value)
    return d

get_style(format)

Infer style from output format.

Source code in ontopy/ontodoc.py
def get_style(format):
    """Infer style from output format."""
    if format == 'simple-html':
        style = 'html'
    elif format in ('tex', 'latex', 'pdf'):
        style = 'markdown_tex'
    else:
        style = 'markdown'
    return style

load_pandoc_option_file(yamlfile)

Loads pandoc options from yamlfile and return a list with corresponding pandoc command line arguments.

Source code in ontopy/ontodoc.py
def load_pandoc_option_file(yamlfile):
    """Loads pandoc options from `yamlfile` and return a list with
    corresponding pandoc command line arguments."""
    with open(yamlfile) as f:
        d = yaml.safe_load(f)
    options = d.pop('input-files', [])
    variables = d.pop('variables', {})

    for k, v in d.items():
        if isinstance(v, bool):
            if v:
                options.append('--%s' % k)
        else:
            options.append('--%s=%s' % (k, v))

    for k, v in variables.items():
        if k == 'date' and v == 'now':
            v = time.strftime('%B %d, %Y')
        options.append('--variable=%s:%s' % (k, v))

    return options

run_pandoc(genfile, outfile, format, pandoc_option_files=(), pandoc_options=(), verbose=True)

Runs pandoc.

Parameters

genfile : str Name of markdown input file. outfile : str Output file name. format : str Output format. pandoc_option_files : sequence List of files with additional pandoc options. Default is to read "pandoc-options.yaml" and "pandoc-FORMAT-options.yml", where FORMAT is the output format. pandoc_options : sequence Additional pandoc options overriding options read from pandoc_option_files. verbose : bool Whether to print the pandoc command before execution.

Raises

subprocess.CalledProcessError If the pandoc process returns with non-zero status. The returncode attribute will hold the exit code.

Source code in ontopy/ontodoc.py
def run_pandoc(genfile, outfile, format, pandoc_option_files=(),
               pandoc_options=(), verbose=True):
    """Runs pandoc.

    Parameters
    ----------
    genfile : str
        Name of markdown input file.
    outfile : str
        Output file name.
    format : str
        Output format.
    pandoc_option_files : sequence
        List of files with additional pandoc options.  Default is to read
        "pandoc-options.yaml" and "pandoc-FORMAT-options.yml", where
        `FORMAT` is the output format.
    pandoc_options : sequence
        Additional pandoc options overriding options read from
        `pandoc_option_files`.
    verbose : bool
        Whether to print the pandoc command before execution.

    Raises
    ------
    subprocess.CalledProcessError
        If the pandoc process returns with non-zero status.  The `returncode`
        attribute will hold the exit code.
    """
    # Create pandoc argument list
    args = [genfile]
    files = ['pandoc-options.yaml', 'pandoc-%s-options.yaml' % format]
    if pandoc_option_files:
        files = pandoc_option_files
    for fname in files:
        if os.path.exists(fname):
            args.extend(load_pandoc_option_file(fname))
        else:
            warnings.warn('missing pandoc option file: %s' % fname)

    # Update pandoc argument list
    args = append_pandoc_options(args, pandoc_options)

    # pdf output requires a special attention...
    if format == 'pdf':
        pdf_engine = 'pdflatex'
        for arg in args:
            if arg.startswith('--pdf-engine'):
                pdf_engine = arg.split('=', 1)[1]
                break
        with TemporaryDirectory() as tmpdir:
            run_pandoc_pdf(tmpdir, pdf_engine, outfile, args, verbose=verbose)
    else:
        args.append('--output=%s' % outfile)
        cmd = ['pandoc'] + args
        if verbose:
            print()
            print('* Executing command:')
            print(' '.join(shlex.quote(s) for s in cmd))
        subprocess.check_call(cmd)

run_pandoc_pdf(latex_dir, pdf_engine, outfile, args, verbose=True)

Run pandoc for pdf generation.

Source code in ontopy/ontodoc.py
def run_pandoc_pdf(latex_dir, pdf_engine, outfile, args, verbose=True):
    """Run pandoc for pdf generation."""
    basename = os.path.join(latex_dir, os.path.splitext(
        os.path.basename(outfile))[0])

    # Run pandoc
    texfile = basename + '.tex'
    args.append('--output=%s' % texfile)
    cmd = ['pandoc'] + args
    if verbose:
        print()
        print('* Executing commands:')
        print(' '.join(shlex.quote(s) for s in cmd))
    subprocess.check_call(cmd)

    # Fixing tex output
    texfile2 = basename + '2.tex'
    with open(texfile, 'rt') as f:
        content = f.read().replace(r'\$\Uptheta\$', r'$\Uptheta$')
    with open(texfile2, 'wt') as f:
        f.write(content)

    # Run latex
    pdffile = basename + '2.pdf'
    cmd = [pdf_engine, texfile2, '-halt-on-error',
           '-output-directory=%s' % latex_dir]
    if verbose:
        print()
        print(' '.join(shlex.quote(s) for s in cmd))
    output = subprocess.check_output(cmd, timeout=60)
    output = subprocess.check_output(cmd, timeout=60)

    # Workaround for non-working "-output-directory" latex option
    if not os.path.exists(pdffile):
        if os.path.exists(os.path.basename(pdffile)):
            pdffile = os.path.basename(pdffile)
            for ext in 'aux', 'out', 'toc', 'log':
                filename = os.path.splitext(pdffile)[0] + '.' + ext
                if os.path.exists(filename):
                    os.remove(filename)
        else:
            print()
            print(output)
            print()
            raise RuntimeError('latex did not produce pdf file: ' + pdffile)

    # Copy pdffile
    if not os.path.exists(outfile) or not os.path.samefile(pdffile, outfile):
        if verbose:
            print()
            print('move %s to %s' % (pdffile, outfile))
        shutil.move(pdffile, outfile)
Back to top