Browse Source

Document SmartList, StringMixIn, utils; some cleanup.

tags/v0.1
Ben Kurtovic 12 years ago
parent
commit
d9805d409b
4 changed files with 106 additions and 4 deletions
  1. +64
    -0
      mwparserfromhell/smart_list.py
  2. +20
    -0
      mwparserfromhell/string_mixin.py
  3. +21
    -2
      mwparserfromhell/utils.py
  4. +1
    -2
      mwparserfromhell/wikicode.py

+ 64
- 0
mwparserfromhell/smart_list.py View File

@@ -20,13 +20,54 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
This module contains the :py:class:`~mwparserfromhell.smart_list.SmartList`
type, as well as its :py:class:`~mwparserfromhell.smart_list._ListProxy` child,
which together implement a list whose sublists reflect changes made to the main
list, and vice-versa.
"""

from __future__ import unicode_literals

from .compat import maxsize, py3k

__all__ = ["SmartList"]

def inheritdoc(method):
"""Set __doc__ of *method* to __doc__ of *method* in its parent class.

Since this is used on
:py:class:`~mwparserfromhell.smart_list.SmartList`, the "parent class" used
is ``list``. This function can be used as a decorator.
"""
method.__doc__ = getattr(list, method.__name__).__doc__
return method


class SmartList(list):
"""Implements the ``list`` interface with special handling of sublists.

When a sublist is created (through list[i:j]), any changes made to this
list (such as the addition, removal, or replacement of elements) will be
reflected in the sublist, or vice-versa, to the greatest degree possible.
This is implemented by having sublists - instances of the
:py:class:`~mwparserfromhell.smart_list._ListProxy` type - dynamically
determine their elements by storing their slice info and retrieving that
slice from the parent. Methods that change the size of the list also change
the slice info. For example::

>>> parent = SmartList([0, 1, 2, 3])
>>> parent
[0, 1, 2, 3]
>>> child = parent[2:]
>>> child
[2, 3]
>>> child.append(4)
>>> child
[2, 3, 4]
>>> parent
[0, 1, 2, 3, 4]
"""
def __init__(self, iterable=None):
if iterable:
super(SmartList, self).__init__(iterable)
@@ -88,17 +129,21 @@ class SmartList(list):
self.extend(other)
return self

@inheritdoc
def append(self, item):
head = len(self)
self[head:head] = [item]

@inheritdoc
def extend(self, item):
head = len(self)
self[head:head] = item

@inheritdoc
def insert(self, index, item):
self[index:index] = [item]

@inheritdoc
def pop(self, index=None):
if index is None:
index = len(self) - 1
@@ -106,15 +151,18 @@ class SmartList(list):
del self[index]
return item

@inheritdoc
def remove(self, item):
del self[self.index(item)]

@inheritdoc
def reverse(self):
copy = list(self)
for child in self._children:
child._parent = copy
super(SmartList, self).reverse()

@inheritdoc
def sort(self, cmp=None, key=None, reverse=None):
copy = list(self)
for child in self._children:
@@ -132,6 +180,13 @@ class SmartList(list):


class _ListProxy(list):
"""Implement the ``list`` interface by getting elements from a parent.

This is created by a :py:class:`~mwparserfromhell.smart_list.SmartList`
object when slicing. It does not actually store the list at any time;
instead, whenever the list is needed, it builds it dynamically using the
:py:meth:`_render` method.
"""
def __init__(self, parent, sliceinfo):
super(_ListProxy, self).__init__()
self._parent = parent
@@ -249,12 +304,15 @@ class _ListProxy(list):
def _render(self):
return list(self._parent)[self._start:self._stop:self._step]

@inheritdoc
def append(self, item):
self._parent.insert(self._stop, item)

@inheritdoc
def count(self, item):
return self._render().count(item)

@inheritdoc
def index(self, item, start=None, stop=None):
if start is not None:
if stop is not None:
@@ -262,26 +320,32 @@ class _ListProxy(list):
return self._render().index(item, start)
return self._render().index(item)

@inheritdoc
def extend(self, item):
self._parent[self._stop:self._stop] = item

@inheritdoc
def insert(self, index, item):
self._parent.insert(self._start + index, item)

@inheritdoc
def pop(self, index=None):
if index is None:
index = len(self) - 1
return self._parent.pop(self._start + index)

@inheritdoc
def remove(self, item):
index = self.index(item)
del self._parent[index]

@inheritdoc
def reverse(self):
item = self._render()
item.reverse()
self._parent[self._start:self._stop:self._step] = item

@inheritdoc
def sort(self, cmp=None, key=None, reverse=None):
item = self._render()
if cmp is not None:


+ 20
- 0
mwparserfromhell/string_mixin.py View File

@@ -20,6 +20,12 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
This module contains the :py:class:`~mwparserfromhell.string_mixin.StringMixIn`
type, which implements the interface for the ``unicode`` type (``str`` on py3k)
in a dynamic manner.
"""

from __future__ import unicode_literals

from .compat import py3k, str
@@ -27,11 +33,25 @@ from .compat import py3k, str
__all__ = ["StringMixIn"]

def inheritdoc(method):
"""Set __doc__ of *method* to __doc__ of *method* in its parent class.

Since this is used on
:py:class:`~mwparserfromhell.string_mixin.StringMixIn`, the "parent class"
used is ``str``. This function can be used as a decorator.
"""
method.__doc__ = getattr(str, method.__name__).__doc__
return method


class StringMixIn(object):
"""Implement the interface for ``unicode``/``str`` in a dynamic manner.

To use this class, inherit from it and override the :py:meth:`__unicode__`
method (same on py3k) to return the string representation of the object.
The various string methods will operate on the value of
:py:meth:`__unicode__` instead of the immutable ``self`` like the regular
``str`` type.
"""
if py3k:
def __str__(self):
return self.__unicode__()


+ 21
- 2
mwparserfromhell/utils.py View File

@@ -20,6 +20,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
This module contains accessory functions that wrap around existing ones to
provide additional functionality.
"""

from __future__ import unicode_literals

import mwparserfromhell
@@ -28,15 +33,29 @@ from .nodes import Node
from .smart_list import SmartList

def parse_anything(value):
"""Return a :py:class:`~mwparserfromhell.wikicode.Wikicode` for *value*.

This differs from :py:func:`mwparserfromhell.parse` in that we accept more
than just a string to be parsed. Unicode objects (strings in py3k), strings
(bytes in py3k), integers (converted to strings), ``None``, existing
:py:class:`~mwparserfromhell.nodes.Node` or
:py:class:`~mwparserfromhell.wikicode.Wikicode` objects, as well as an
iterable of these types, are supported. This is used to parse input
on-the-fly by various methods of
:py:class:`~mwparserfromhell.wikicode.Wikicode` and others like
:py:class:`~mwparserfromhell.nodes.template.Template`, such as
:py:meth:`wikicode.insert() <mwparserfromhell.wikicode.Wikicode.insert>`
or setting :py:meth:`template.name
<mwparserfromhell.nodes.template.Template.name>`.
"""
wikicode = mwparserfromhell.wikicode.Wikicode
if isinstance(value, wikicode):
return value
elif isinstance(value, Node):
return wikicode(SmartList([value]))
elif isinstance(value, basestring):
elif isinstance(value, str):
return mwparserfromhell.parse(value)
elif isinstance(value, bytes):
# This should only happen in py3k when bytes is not in basestring:
return mwparserfromhell.parse(value.decode("utf8"))
elif isinstance(value, int):
return mwparserfromhell.parse(str(value))


+ 1
- 2
mwparserfromhell/wikicode.py View File

@@ -316,8 +316,7 @@ class Wikicode(StringMixIn):
"""Iterate over template nodes.

This is equivalent to :py:meth:`ifilter` with *forcetype* set to
:py:class:`~mwparserfromhell.nodes.template.Template`. It takes all
other arguments passable to :py:meth:`ifilter`.
:py:class:`~mwparserfromhell.nodes.template.Template`.
"""
return self.filter(recursive, matches, flags, forcetype=Template)



Loading…
Cancel
Save