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 tobasedir
. 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 topath
. The default path isfigdir
/name
, wherefigdir
is given at class initiation. It is recommended to exclude the file extension frompath
. 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)