diff --git a/mwparserfromhell/wikicode.py b/mwparserfromhell/wikicode.py index 0154775..97636fe 100644 --- a/mwparserfromhell/wikicode.py +++ b/mwparserfromhell/wikicode.py @@ -44,21 +44,21 @@ class Wikicode(StringMixIn): return "".join([str(node) for node in self.nodes]) def _get_children(self, node): - """Iterate over all descendants of a given node, including itself. + """Iterate over all descendants of a given *node*, including itself. - This is implemented by the __iternodes__() generator of Node classes, - which by default yields itself and nothing more. + This is implemented by the ``__iternodes__()`` generator of ``Node`` + classes, which by default yields itself and nothing more. """ for context, child in node.__iternodes__(self._get_all_nodes): yield child def _get_context(self, node, obj): - """Return a ``Wikicode`` that contains ``obj`` in its descendants. + """Return a ``Wikicode`` that contains *obj* in its descendants. - The closest (shortest distance from ``node``) suitable ``Wikicode`` - will be returned, or ``None`` if the ``obj`` is the ``node`` itself. + The closest (shortest distance from *node*) suitable ``Wikicode`` will + be returned, or ``None`` if the *obj* is the *node* itself. - Raises ``ValueError`` if ``obj`` is not within ``node``. + Raises ``ValueError`` if *obj* is not within *node*. """ for context, child in node.__iternodes__(self._get_all_nodes): if child is obj: @@ -76,7 +76,10 @@ class Wikicode(StringMixIn): yield child def _is_equivalent(self, obj, node): - """Return ``True`` if obj and node are equivalent, otherwise ``False``. + """Return ``True`` if *obj* and *node* are equivalent, else ``False``. + + If *obj* is a ``Node``, the function will test whether they are the + same object, otherwise it will compare them with ``==``. """ if isinstance(obj, Node): if node is obj: @@ -87,16 +90,28 @@ class Wikicode(StringMixIn): return False def _contains(self, nodes, obj): + """Return ``True`` if *obj* is inside of *nodes*, else ``False``. + + If *obj* is a ``Node``, we will only return ``True`` if *obj* is + actually in the list (and not just a node that equals it). Otherwise, + the test is simply ``obj in nodes``. + """ if isinstance(obj, Node): for node in nodes: if node is obj: return True - else: - if obj in nodes: - return True - return False + return False + return obj in nodes def _do_search(self, obj, recursive, callback, context, *args, **kwargs): + """Look within *context* for *obj*, executing *callback* if found. + + If *recursive* is ``True``, we'll look within context and its + descendants, otherwise we'll just execute callback. We raise + :py:exc:`ValueError` if *obj* isn't in our node list or context. If + found, *callback* is passed the context, the index of the node within + the context, and whatever were passed as ``*args`` and ``**kwargs``. + """ if recursive: for i, node in enumerate(context.nodes): if self._is_equivalent(obj, node): @@ -110,6 +125,16 @@ class Wikicode(StringMixIn): callback(context, self.index(obj, recursive=False), *args, **kwargs) def _get_tree(self, code, lines, marker, indent): + """Build a tree to illustrate the way the Wikicode object was parsed. + + The method that builds the actual tree is ``__showtree__`` of ``Node`` + objects. *code* is the ``Wikicode`` object to build a tree for. *lines* + is the list to append the tree to, which is returned at the end of the + method. *marker* is some object to be used to indicate that the builder + should continue on from the last line instead of starting a new one; it + should be any object that can be tested for with ``is``. *indent* is + the starting indentation. + """ def write(*args): if lines and lines[-1] is marker: # Continue from the last line lines.pop() # Remove the marker @@ -126,6 +151,11 @@ class Wikicode(StringMixIn): @property def nodes(self): + """A list of :py:class:`~mwparserfromhell.nodes.Node` objects. + + This is the internal data actually stored within a + :py:class:`~mwparserfromhell.wikicode.Wikicode` object. + """ return self._nodes @nodes.setter @@ -133,9 +163,18 @@ class Wikicode(StringMixIn): self._nodes = value def get(self, index): + """Return the *index*\ th node within the list of nodes.""" return self.nodes[index] def set(self, index, value): + """Set the ``Node`` at *index* to *value*. + + Raises :py:exc:`IndexError` if *index* is out of range, or + :py:exc:`ValueError` if *value* cannot be coerced into one + :py:class:`~mwparserfromhell.nodes.Node`. To insert multiple nodes at + an index, use :py:meth:`get` with either :py:meth:`remove` and + :py:meth:`insert` or :py:meth:`replace`. + """ nodes = parse_anything(value).nodes if len(nodes) > 1: raise ValueError("Cannot coerce multiple nodes into one index") @@ -146,6 +185,13 @@ class Wikicode(StringMixIn): self.nodes[index] = nodes[0] def index(self, obj, recursive=False): + """Return the index of *obj* in the list of nodes. + + Raises :py:exc:`ValueError` if *obj* is not found. If *recursive* is + ``True``, we will look in all nodes of ours and their descendants, and + return the index of our direct descendant node within *our* list of + nodes. Otherwise, the lookup is done only on direct descendants. + """ if recursive: for i, node in enumerate(self.nodes): if self._contains(self._get_children(node), obj): @@ -158,15 +204,40 @@ class Wikicode(StringMixIn): raise ValueError(obj) def insert(self, index, value): + """Insert *value* at *index* in the list of nodes. + + *value* can be anything parasable by + :py:func:`mwparserfromhell.utils.parse_anything`, which includes + strings or other :py:class:`~mwparserfromhell.wikicode.Wikicode` or + :py:class:`~mwparserfromhell.nodes.Node` objects. + """ nodes = parse_anything(value).nodes for node in reversed(nodes): self.nodes.insert(index, node) def insert_before(self, obj, value, recursive=True): + """Insert *value* immediately before *obj* in the list of nodes. + + *value* can be anything parasable by + :py:func:`mwparserfromhell.utils.parse_anything`. If *recursive* is + ``True``, we will try to find *obj* within our child nodes even if it + is not a direct descendant of this + :py:class:`~mwparserfromhell.wikicode.Wikicode` object. If *obj* is not + in the node list, :py:exc:`ValueError` is raised. + """ callback = lambda self, i, value: self.insert(i, value) self._do_search(obj, recursive, callback, self, value) def insert_after(self, obj, value, recursive=True): + """Insert *value* immediately after *obj* in the list of nodes. + + *value* can be anything parasable by + :py:func:`mwparserfromhell.utils.parse_anything`. If *recursive* is + ``True``, we will try to find *obj* within our child nodes even if it + is not a direct descendant of this + :py:class:`~mwparserfromhell.wikicode.Wikicode` object. If *obj* is not + in the node list, :py:exc:`ValueError` is raised. + """ callback = lambda self, i, value: self.insert(i + 1, value) self._do_search(obj, recursive, callback, self, value)