import pyparsing as pp
import StringIO
from qfile import QOpen
+from string import Template
+
+# useful things for pyparsing
+def returnList(x):
+ def listify(s, loc, toks):
+ return [toks]
+ x.setParseAction(listify)
+ return x
+def returnTuple(x):
+ def listify(s, loc, toks):
+ return [tuple(toks)]
+ x.setParseAction(listify)
+ return x
+def CommaList(word):
+ return returnList(pp.Optional(word + pp.ZeroOrMore(pp.Suppress(',') + word)))
+def sl(s):
+ return pp.Suppress(pp.Literal(s))
import pythonapi
class SphinxWriter:
- def __init__(self, filename, language):
+ def __init__(self, filename, language, abspath):
assert language in ['py', 'c', 'cpp']
self.language = language
+ self.abspath = abspath
+ os.path.abspath(os.path.dirname(filename))
+
self.f_index = QOpen(os.path.join(self.language, filename), 'wt')
self.f = self.f_index
self.f_chapter = None
self.state = None
self.envstack = []
self.tags = {}
- self.errors = open('errors', 'wt')
+ self.errors = open('errors.%s' % language, 'wt')
self.unhandled_commands = set()
self.freshline = True
self.function_props = {}
s = ":math:`%s`" % s[1:-1].strip()
elif self.state != 'math':
s.replace('\\_', '_')
+ if len(s) > 0 and s[-1] == '\n':
+ s = s[:-1]
if self.state == 'fpreamble':
self.description += s
else:
self.state = None
self.write('\n\n')
else:
- if c.cmd == '[':
- meth = self.cmd_gomath
+ if c.cmd == '\n':
+ self.write('\\\n')
else:
- cname = "cmd_" + c.cmd
- meth = getattr(self, cname, self.unrecognized_cmd)
- meth(c)
+ if c.cmd == '[':
+ meth = self.cmd_gomath
+ else:
+ cname = "cmd_" + c.cmd
+ meth = getattr(self, cname, self.unrecognized_cmd)
+ meth(c)
def cmd_gomath(self, c):
self.state = 'math'
self.f_section = QOpen(os.path.join(self.language, filename + '.rst'), 'wt')
self.f = self.f_section
self.indent = 0
- title = str(c.params[0])
+ title = self.render(c.params[0].str)
print >>self, title
print >>self, '=' * len(title)
print >>self
def cmd_subsection(self, c):
print >>self
- print >>self, str(c.params[0])
- print >>self, '-' * len(str(c.params[0]))
+ nm = str(c.params[0])
+ print >>self, nm
+ print >>self, '-' * len(nm)
print >>self
self.function_props = {}
+ self.covered.add(nm)
def cmd_includegraphics(self, c):
filename = os.path.join('..', '..', str(c.params[0]))
print >>self, "\n\n.. image:: %s\n\n" % filename
def cmd_cvCppCross(self, c):
- self.write(":ref:`%s`" % str(c.params[0]))
+ self.write(":func:`%s`" % str(c.params[0]))
def cmd_cvCPyCross(self, c):
self.write(":ref:`%s`" % str(c.params[0]))
print >>self, ".. ctype:: " + nm + "\n"
print >>self
self.addtag(nm, c)
+ self.state = 'class'
def addtag(self, nm, c):
if nm == "":
self.indent = 0
nm = self.render(c.params[0].str)
print >>self, "\n.. index:: %s\n" % nm
- print >>self, ".. _%s:\n" % nm
- print >>self, nm
- print >>self, '-' * len(nm)
+ if 0:
+ print >>self, "\n.. _%s:\n" % nm
+ print >>self
+ print >>self, 'cv::%s' % nm
+ print >>self, '-' * (4+len(nm))
print >>self
self.state = 'fpreamble'
if self.description != "":
return
s = str(c.params[0]).replace('\\_', '_')
s = s.replace('\\par', '')
+ s = s.replace('\n', ' ')
s = s.replace(';', '')
self.indent = 0
- print >>self, ".. cfunction:: " + s + "\n"
+ for proto in s.split('\\newline'):
+ if proto.strip() != "":
+ print >>self, "\n\n.. cfunction:: " + proto.strip() + "\n"
# print >>self, "=", repr(c.params[0].str)
print >>self, ' ' + self.description
self.description = ""
return
s = str(c.params[0]).replace('\\_', '_')
s = s.replace('\\par', '')
+ s = s.replace('\n', ' ')
s = s.replace(';', '')
self.indent = 0
for proto in s.split('\\newline'):
self.function_props['defpy'] = s
pp.ParserElement.setDefaultWhitespaceChars(" \n\t")
- def returnList(x):
- def listify(s, loc, toks):
- return [toks]
- x.setParseAction(listify)
- return x
- def CommaList(word):
- return returnList(pp.Optional(word + pp.ZeroOrMore(pp.Suppress(',') + word)))
- def sl(s):
- return pp.Suppress(pp.Literal(s))
ident = pp.Word(pp.alphanums + "_.+-")
ident_or_tuple = ident | (sl('(') + CommaList(ident) + sl(')'))
else:
doc_outs = l[2]
if len(outs) != len(doc_outs):
- self.report_error(c, "function %s output documented tuple %d, code %d" % (l[0], len(outs), len(doc_outs)))
+ self.report_error(c, "function %s output code tuple %d, documented %d" % (l[0], len(outs), len(doc_outs)))
else:
# self.report_error(c, "function %s documented but not found in code" % l[0])
pass
self.report_error(c, "No cvdefPy for function %s" % self.function_props['name'])
self.indent += 1
elif s == 'lstlisting':
- print >>self, "\n::\n"
- self.indent += 1
+ # Set indent to zero while collecting code; so later write will not double-indent
+ self.saved_f = self.f
+ self.saved_indent = self.indent
+ self.f = StringIO.StringIO()
+ self.indent = 0
elif s in ['itemize', 'enumerate']:
self.indent += 1
elif s == 'tabular':
self.f = self.f_section
self.f.write(self.handle_table(tabletxt))
elif s == 'lstlisting':
+ listing = self.f.getvalue()
+
+ self.f = self.saved_f
+ self.indent = self.saved_indent
print >>self
+ if self.language == 'py':
+ ckeys = ['#define', 'void', '#include', ';\n']
+ found = [repr(k) for k in ckeys if k in listing]
+ if len(found) > 0:
+ self.report_error(c, 'listing is probably C, found %s' % ",".join(found))
+ if (self.language == 'py') and ('>>>' in listing):
+ print >>self, "\n.. doctest::\n"
+ else:
+ print >>self, "\n::\n"
+ self.indent += 1
+ print >>self
+ self.write(listing)
self.indent -= 1
print >>self
+ print >>self
print >>self, ".." # otherwise a following :param: gets treated as more listing
elif s == 'document':
pass
def cmd_lstinputlisting(self, c):
s = str(c.params[0])
- print >>self.f, ".. include:: %s" % os.path.join('..', s)
+ print >>self.f, ".. include:: %s" % os.path.normpath(os.path.join(self.abspath, s))
print >>self.f, " :literal:"
print >>self.f
if len(c.params) != 2:
self.report_error(c, "Malformed cvarg")
return
- is_func_arg = self.ee() == ['description'] and not 'done' in self.function_props
+ e = self.ee()
+ if self.state == 'class':
+ nm = self.render(c.params[0].str)
+ if '->' in nm:
+ print >>self, "\n\n.. method:: %s\n\n" % nm
+ else:
+ print >>self, "\n\n.. attribute:: %s\n\n" % nm
+ self.indent += 1
+ print >>self
+ self.doL(c.params[1].str, False)
+ self.indent -= 1
+ print >>self
+ return
+ is_func_arg = (e == ['description']) and (not 'done' in self.function_props)
if is_func_arg:
nm = self.render(c.params[0].str)
print >>self, '\n:param %s: ' % nm,
type = arg.ty
else:
self.report_error(c, 'cannot find arg %s in code' % nm)
- elif self.ee() == ['description']:
- print >>self, '\n* **%s** ' % self.render(c.params[0].str),
- elif self.ee() == ['description', 'description']:
+ elif len(e) > 0 and e[-1] == 'description':
print >>self, '\n* **%s** ' % self.render(c.params[0].str),
else:
- print 'strange env', self.envstack
+ self.report_error(c, "unexpected env (%s) for cvarg" % ",".join(e))
self.indent += 1
self.doL(c.params[1].str, False)
self.indent -= 1
"cvarrseq" : ":class:`CvArr` or :class:`CvSeq`",
"CvPoint2D32fs" : "sequence of (float, float)",
"pts_npts_contours" : "list of lists of (x,y) pairs",
+ "CvSeqOfCvSURFPoint" : ":class:`CvSeq` of :class:`CvSURFPoint`",
+ "CvSeqOfCvSURFDescriptor" : ":class:`CvSeq` of list of float",
+ "cvpoint2d32f_count" : "int",
+ "ranges" : "list of tuples of ints",
+ "PyObject" : "object",
+ "edgeorpoint" : ":class:`CvSubdiv2DEdge`, :class:`CvSubdiv2DPoint`",
}
print >>self, "\n:type %s: %s" % (nm, translate.get(type, ':class:`%s`' % type))
def cmd_genc(self, c): pass
def cmd_genpy(self, c): pass
def cmd_author(self, c): pass
- def cmd_cite(self, c): pass
def cmd_date(self, c): pass
def cmd_def(self, c): pass
def cmd_documentclass(self, c): pass
def cmd_hline(self, c):
print >>self, "\\hline"
+ def cmd_cite(self, c):
+ self.write("[%s]_" % str(c.params[0]))
+
def cmd_href(self, c):
if len(c.params) == 2:
- self.write("`%s <%s>`_" % (str(c.params[1]), str(c.params[0])))
+ self.write("`%s <%s>`_" % (str(c.params[1]), self.render(c.params[0].str)))
else:
self.report_error(c, "href should have two params")
self.write(repr(c))
def unrecognized_cmd(self, c):
- if self.f == self.f_section:
- self.write(repr(c))
- self.unhandled_commands.add(c.cmd)
+ # if writing the index or chapter heading, anything goes
+ if not self.f in [self.f_index, self.f_chapter]:
+ self.write(c.cmd)
+ if (not 'lstlisting' in self.ee()) and (not c.cmd in "#{}%&*\\_"):
+ if not c.cmd in self.unhandled_commands:
+ self.report_error(c, 'unhandled command %s' % c.cmd)
+ self.unhandled_commands.add(c.cmd)
def doL(self, L, newlines = True):
for x in L:
+ pos0 = self.f.tell()
if isinstance(x, TexCmd):
self.docmd(x)
else:
self.doplain(x)
else:
self.doplain(x.lstrip())
- if self.state in ['math'] or not newlines:
- self.appendspace()
- else:
- self.write('\n')
+ pos1 = self.f.tell()
+ if pos0 != pos1:
+ if self.state in ['math'] or not newlines:
+ self.appendspace()
+ else:
+ if not 'lstlisting' in self.ee():
+ self.write('\n')
def handle_table(self, s):
oneline = s.replace('\n', ' ').strip()
if self.envstack != []:
print >>self.errors, "Error envstack not empty at end of doc: " + repr(self.envstack)
- print >>self.errors, "unrecognized commands:"
- print >>self.errors, "\n ".join(sorted(self.unhandled_commands))
+ print >>self.errors, "Unrecognized commands:"
+ for c in sorted(self.unhandled_commands):
+ print >>self.errors, "\n " + c
print >>self.errors
- print >>self.errors, "The following functions are undocumented"
- for f in sorted(set(python_api) - self.covered):
- print >>self.errors, ' ', f
+ if self.language == 'py':
+ print >>self.errors, "The following functions are undocumented"
+ for f in sorted(set(python_api) - self.covered):
+ print >>self.errors, ' ', f
+ print >>self.f_index, " bibliography"
print >>self.f_index, """
Indices and tables
* :ref:`search`
"""
+# Quick and dirty bibtex parser
+
+def parseBib(filename, language):
+ pp.ParserElement.setDefaultWhitespaceChars(" \n\t")
+ entry = returnList(pp.Word('@', pp.alphanums) + sl('{') +
+ pp.Word(pp.alphanums + "_") + sl(',') +
+ CommaList(returnTuple(pp.Word(pp.alphanums) + sl('=') + pp.QuotedString('{', endQuoteChar = '}'))) +
+ pp.Suppress(pp.Optional(',')) +
+ sl('}'))
+ r = (pp.ZeroOrMore(entry) | pp.Suppress('#' + pp.ZeroOrMore(pp.CharsNotIn('\n'))) + pp.StringEnd()).parseFile(filename)
+
+ bibliography = QOpen(os.path.join(language, "bibliography.rst"), 'wt')
+ print >>bibliography, "Bibliography"
+ print >>bibliography, "============"
+ print >>bibliography
+
+ for _,e in sorted([(str(x[1]), x) for x in r]):
+ (etype, tag, attrs) = str(e[0][1:]), str(e[1]), dict([(str(a), str(b)) for (a,b) in e[2]])
+
+ representations = {
+ 'article' : '$author, "$title". $journal $volume $number, pp $pages ($year)',
+ 'inproceedings' : '$author "$title", $booktitle, $year',
+ 'misc' : '$author "$title", $year',
+ 'techreport' : '$author "$title", $edition, $edition ($year)',
+ }
+ if etype in representations:
+ if 0:
+ print >>bibliography, tag
+ print >>bibliography, "^" * len(tag)
+ print >>bibliography
+
+ print >>bibliography, ".. [%s] %s" % (tag, Template(representations[etype]).safe_substitute(attrs))
+ print >>bibliography
+ bibliography.close()
+
if 1:
- sources = ['../' + f for f in os.listdir('..') if f.endswith('.tex')]
- if distutils.dep_util.newer_group(["latexparser.py"] + sources, "pickled"):
- fulldoc = latexparser(sys.argv[1], 0)
- pickle.dump(fulldoc, open("pickled", 'wb'))
- raw = open('fulldoc', 'w')
- for x in fulldoc:
- print >>raw, repr(x)
- raw.close()
- else:
- fulldoc = pickle.load(open("pickled", "rb"))
+ fulldoc = latexparser(sys.argv[1])
+
+ abspath = os.path.abspath(os.path.dirname(sys.argv[1]))
+
+ raw = open('raw.full', 'w')
+ for x in fulldoc:
+ print >>raw, repr(x)
+ raw.close()
# Filter on target language
def preprocess_conditionals(fd, conditionals):
return r
tags = {}
- for language in ['c', 'cpp', 'py']:
+ for language in sys.argv[2:]:
doc = preprocess_conditionals(fulldoc, {
'C' : language=='c',
'Python' : language=='py',
for x in doc:
print >>raw, repr(x)
raw.close()
- sr = SphinxWriter('index.rst', language)
+ sr = SphinxWriter('index.rst', language, abspath)
print >>sr, """
OpenCV |version| %s Reference
=================================
""" % {'c': 'C', 'cpp': 'C++', 'py': 'Python'}[language]
sr.doL(doc)
sr.close()
+ parseBib('../opencv.bib', language)
tags.update(sr.get_tags())
open('TAGS', 'w').write("\n".join(sorted(tags.values())) + "\n")