Skip to content

attr_list

Attribute List Extension for Python-Markdown.

Adds attribute list syntax. Inspired by maruku's feature of the same name.

See https://pythonhosted.org/Markdown/extensions/attr_list.html for documentation.

Original code Copyright 2011 Waylan Limberg.

All changes Copyright 2011-2014 The Python Markdown Project

License: BSD

Classes

AttrListTreeprocessor(markdown_instance=None)

Bases: Treeprocessor

Attribute List Tree processor.

Source code in pyrevitlib/pyrevit/coreutils/markdown/util.py
def __init__(self, markdown_instance=None):
    if markdown_instance:
        self.markdown = markdown_instance

Attributes

markdown = markdown_instance instance-attribute
BASE_RE = '\\{\\:?([^\\}\\n]*)\\}' class-attribute instance-attribute
HEADER_RE = re.compile('[ ]+%s[ ]*$' % BASE_RE) class-attribute instance-attribute
BLOCK_RE = re.compile('\\n[ ]*%s[ ]*$' % BASE_RE) class-attribute instance-attribute
INLINE_RE = re.compile('^%s' % BASE_RE) class-attribute instance-attribute
NAME_RE = re.compile('[^A-Z_a-z\\u00c0-\\u00d6\\u00d8-\\u00f6\\u00f8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c-\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\:\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040]+') class-attribute instance-attribute

Functions

run(doc)
Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def run(self, doc):
    for elem in doc.iter():
        if isBlockLevel(elem.tag):
            # Block level: check for attrs on last line of text
            RE = self.BLOCK_RE
            if isheader(elem) or elem.tag == 'dt':
                # header or def-term: check for attrs at end of line
                RE = self.HEADER_RE
            if len(elem) and elem.tag == 'li':
                # special case list items. children may include a ul or ol.
                pos = None
                # find the ul or ol position
                for i, child in enumerate(elem):
                    if child.tag in ['ul', 'ol']:
                        pos = i
                        break
                if pos is None and elem[-1].tail:
                    # use tail of last child. no ul or ol.
                    m = RE.search(elem[-1].tail)
                    if m:
                        self.assign_attrs(elem, m.group(1))
                        elem[-1].tail = elem[-1].tail[:m.start()]
                elif pos is not None and pos > 0 and elem[pos-1].tail:
                    # use tail of last child before ul or ol
                    m = RE.search(elem[pos-1].tail)
                    if m:
                        self.assign_attrs(elem, m.group(1))
                        elem[pos-1].tail = elem[pos-1].tail[:m.start()]
                elif elem.text:
                    # use text. ul is first child.
                    m = RE.search(elem.text)
                    if m:
                        self.assign_attrs(elem, m.group(1))
                        elem.text = elem.text[:m.start()]
            elif len(elem) and elem[-1].tail:
                # has children. Get from tail of last child
                m = RE.search(elem[-1].tail)
                if m:
                    self.assign_attrs(elem, m.group(1))
                    elem[-1].tail = elem[-1].tail[:m.start()]
                    if isheader(elem):
                        # clean up trailing #s
                        elem[-1].tail = elem[-1].tail.rstrip('#').rstrip()
            elif elem.text:
                # no children. Get from text.
                m = RE.search(elem.text)
                if not m and elem.tag == 'td':
                    m = re.search(self.BASE_RE, elem.text)
                if m:
                    self.assign_attrs(elem, m.group(1))
                    elem.text = elem.text[:m.start()]
                    if isheader(elem):
                        # clean up trailing #s
                        elem.text = elem.text.rstrip('#').rstrip()
        else:
            # inline: check for attrs at start of tail
            if elem.tail:
                m = self.INLINE_RE.match(elem.tail)
                if m:
                    self.assign_attrs(elem, m.group(1))
                    elem.tail = elem.tail[m.end():]
assign_attrs(elem, attrs)

Assign attrs to element.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def assign_attrs(self, elem, attrs):
    """Assign attrs to element."""
    for k, v in get_attrs(attrs):
        if k == '.':
            # add to class
            cls = elem.get('class')
            if cls:
                elem.set('class', '%s %s' % (cls, v))
            else:
                elem.set('class', v)
        else:
            # assign attr k with v
            elem.set(self.sanitize_name(k), v)
sanitize_name(name)

Sanitize name as 'an XML Name, minus the ":"'.

See http://www.w3.org/TR/REC-xml-names/#NT-NCName.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def sanitize_name(self, name):
    """Sanitize name as 'an XML Name, minus the ":"'.

    See http://www.w3.org/TR/REC-xml-names/#NT-NCName.
    """
    return self.NAME_RE.sub('_', name)

AttrListExtension(*args, **kwargs)

Bases: Extension

Attribute List Extension.

Initiate Extension and set up configs.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/__init__.py
def __init__(self, *args, **kwargs):
    """Initiate Extension and set up configs."""
    # check for configs arg for backward compat.
    # (there only ever used to be one so we use arg[0])
    if len(args):
        if args[0] is not None:
            self.setConfigs(args[0])
        warnings.warn('Extension classes accepting positional args is '
                      'pending Deprecation. Each setting should be '
                      'passed into the Class as a keyword. Positional '
                      'args are deprecated and will raise '
                      'an error in version 2.7. See the Release Notes for '
                      'Python-Markdown version 2.6 for more info.',
                      DeprecationWarning)
    # check for configs kwarg for backward compat.
    if 'configs' in kwargs.keys():
        if kwargs['configs'] is not None:
            self.setConfigs(kwargs.pop('configs', {}))
        warnings.warn('Extension classes accepting a dict on the single '
                      'keyword "config" is pending Deprecation. Each '
                      'setting should be passed into the Class as a '
                      'keyword directly. The "config" keyword is '
                      'deprecated and raise an error in '
                      'version 2.7. See the Release Notes for '
                      'Python-Markdown version 2.6 for more info.',
                      DeprecationWarning)
    # finally, use kwargs
    self.setConfigs(kwargs)

Attributes

config = {} class-attribute instance-attribute

Functions

getConfig(key, default='')

Return a setting for the given key or an empty string.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/__init__.py
def getConfig(self, key, default=''):
    """Return a setting for the given key or an empty string."""
    if key in self.config:
        return self.config[key][0]
    else:
        return default
getConfigs()

Return all configs settings as a dict.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/__init__.py
def getConfigs(self):
    """Return all configs settings as a dict."""
    return dict([(key, self.getConfig(key)) for key in self.config.keys()])
getConfigInfo()

Return all config descriptions as a list of tuples.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/__init__.py
def getConfigInfo(self):
    """Return all config descriptions as a list of tuples."""
    return [(key, self.config[key][1]) for key in self.config.keys()]
setConfig(key, value)

Set a config setting for key with the given value.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/__init__.py
def setConfig(self, key, value):
    """Set a config setting for `key` with the given `value`."""
    if isinstance(self.config[key][0], bool):
        value = parseBoolValue(value)
    if self.config[key][0] is None:
        value = parseBoolValue(value, preserve_none=True)
    self.config[key][0] = value
setConfigs(items)

Set multiple config settings given a dict or list of tuples.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/__init__.py
def setConfigs(self, items):
    """Set multiple config settings given a dict or list of tuples."""
    if hasattr(items, 'items'):
        # it's a dict
        items = items.items()
    for key, value in items:
        self.setConfig(key, value)
extendMarkdown(md, md_globals)
Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def extendMarkdown(self, md, md_globals):
    md.treeprocessors.add(
        'attr_list', AttrListTreeprocessor(md), '>prettify'
    )

Functions

get_attrs(str)

Parse attribute list and return a list of attribute tuples.

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def get_attrs(str):
    """Parse attribute list and return a list of attribute tuples."""
    return _scanner.scan(str)[0]

isheader(elem)

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def isheader(elem):
    return elem.tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']

makeExtension(*args, **kwargs)

Source code in pyrevitlib/pyrevit/coreutils/markdown/extensions/attr_list.py
def makeExtension(*args, **kwargs):
    return AttrListExtension(*args, **kwargs)