__author__ = 'Robert Smallshire' class Node(object): def __init__(self, indent=None, lines=None, parent=None): if indent is not None: self.indent = indent else: self.indent = 0 if lines is not None: self.lines = lines else: self.lines = [] self._parent = parent self.children = [] parent = property(lambda self: self._parent) def add_child(self, child): assert(child.parent is self) self.children.append(child) def __repr__(self): return "Node(" + repr(self.indent) + ", " + repr(self.lines) + ", children=" + repr(self.children) + ")" def render_rst(self, *args, **kwargs): result = [] prefix = ' ' * self.indent result.extend(prefix + line for line in self.lines) for child in self.children: result.extend(child.render_rst()) return result class Arg(Node): def __init__(self, indent, child_indent, name): super(Arg, self).__init__(indent) self.child_indent = child_indent self.name = name self.type = None def __repr__(self): return "Arg(" + repr(self.name) + ", " + repr(self.type) + ", children=" + repr(self.children) + ")" def render_rst(self, *args, **kwargs): result = [] indent = ' ' * self.indent # Render the param description description = [] for child in self.children: child_lines = child.render_rst() description.extend(child_lines) dedent = self.child_indent - self.indent name = self.name.replace('*', r'\*') first_description = description[0].lstrip() if len(description) else '' if not first_description: # TODO: Emit a warning about a missing argument description pass result.append("{indent}:param {name}: {first_description}".format(indent=indent, name=name, first_description=first_description)) dedented_body = [line[dedent:] for line in description[1:]] result.extend(dedented_body) # If a type was specified render the type if self.type is not None: result.append("{indent}:type {name}: {type}".format(indent=indent, name=self.name, type=self.type)) result.append('') ensure_terminal_blank(result) return result class Raises(Node): def __init__(self, indent=None): super(Raises, self).__init__(indent=indent) def __repr__(self): return "Raises(" + repr(self.indent) + ", children=" + repr(self.children) + ")" def render_rst(self, *args, **kwargs): result = [] indent = ' ' * self.indent result.append(indent + ':raises:') for child in self.children: result.extend(child.render_rst(only_child=len(self.children) == 1)) ensure_terminal_blank(result) return result class Except(Node): def __init__(self, indent, type): super(Except, self).__init__(indent=indent) #self.child_indent = child_indent self.type = type def __repr__(self): return "Except(" + repr(self.type) + ", children=" + repr(self.children) + ")" def render_rst(self, only_child=False, *args, **kwargs): result = [] indent = ' ' * self.indent # Render the param description description = [] for child in self.children: child_lines = child.render_rst() description.extend(child_lines) #dedent = self.child_indent - self.indent bullet = '* ' if not only_child else '' first_description = description[0].lstrip() if len(description) else '' result.append("{indent}{bullet}{type} - {first_description}".format(indent=indent, bullet=bullet, type=self.type, first_description=first_description)) #dedented_body = [' ' * len(bullet) + line[dedent:] for line in description[1:]] #result.extend(dedented_body) result.extend(description[1:]) ensure_terminal_blank(result) return result class Returns(Node): def __init__(self, indent): super(Returns, self).__init__(indent=indent) self.title = 'Returns' self.line = '' def __repr__(self): return "Returns(" + str(self.indent) + ", children=" + str(self.children) + ")" def render_rst(self, *args, **kwargs): result = [] indent = ' ' * self.indent # Render the param description description = [self.line] if self.line else [] for child in self.children: child_lines = child.render_rst() description.extend(child_lines) self.render_title(description, indent, result) result.extend(description[1:]) ensure_terminal_blank(result) return result def render_title(self, description, indent, result): result.append( "{indent}:returns: {first_description}".format(indent=indent, first_description=description[0].lstrip())) class Warning(Node): def __init__(self, indent): super(Warning, self).__init__(indent=indent) def __repr__(self): return "Warning(" + repr(self.indent) + ", children=" + str(self.children) + ")" def render_rst(self, *args, **kwargs): # TODO: Factor out the commonality between this and Note below result = [] indent = ' ' * self.indent # Render the param description description = [self.line] if self.line else [] for child in self.children: child_lines = child.render_rst() description.extend(child_lines) # Fix the indent on the first line if len(description) > 1 and len(description[1].strip()) != 0: body_indent = len(description[1]) - len(description[1].strip()) else: body_indent = self.indent + 4 if len(description) > 0: description[0] = ' ' * body_indent + description[0] result.append(indent + ".. warning::") result.append(indent + '') result.extend(description) ensure_terminal_blank(result) return result class Note(Node): def __init__(self, indent): super(Note, self).__init__(indent=indent) self.line = '' def __repr__(self): return "Note(" + repr(self.indent) + ", children=" + str(self.children) + ")" def render_rst(self, *args, **kwargs): # TODO: Factor out the commonality between this and Warning above result = [] indent = ' ' * self.indent # Render the param description description = [self.line] if self.line else [] for child in self.children: child_lines = child.render_rst() description.extend(child_lines) # Fix the indent on the first line if len(description) > 1 and len(description[1].strip()) != 0: body_indent = len(description[1]) - len(description[1].strip()) else: body_indent = self.indent + 4 if len(description) > 0: description[0] = ' ' * body_indent + description[0] result.append(indent + ".. note::") result.append(indent + '') result.extend(description) ensure_terminal_blank(result) return result def ensure_terminal_blank(result): '''If the description didn't end with a blank line add one here.''' if len(result) > 0: if len(result[-1].strip()) != 0: result.append('')