bpy.handlers package

Submodules

bpy.handlers.asciidoc module

You can specify embed_images, for example:

handlers = {
  'AsciiDoc': {
    'options': {
      'embed_images': True,
    },
  },
}
class bpy.handlers.asciidoc.Handler(filename, options=None)[source]

Bases: bpy.handlers.base.BaseHandler

Handler for AsciiDoc markup language

>>> handler = Handler(None)
>>> print(handler.generate_header({'title': 'foobar'}))
// !b
// title: foobar
HEADER_FMT = u'// %s: %s'
PREFIX_END = u''
PREFIX_HEAD = u'// '

bpy.handlers.base module

class bpy.handlers.base.BaseHandler(filename, options=None)[source]

Bases: object

The base clase of markup handler

HEADER_FMT = u'%s: %s'
MERGE_HEADERS = (u'service', u'kind', u'blog', u'id', u'url', u'draft')
OPTIONS = {u'smartypants': False, u'markup_prefix': u'', u'id_affix': None, u'markup_suffix': u''}
PREFIX_END = u''
PREFIX_HEAD = u''
RE_HEADER = <_sre.SRE_Pattern object at 0x7f62f0f65030>
RE_IMG = <_sre.SRE_Pattern object at 0x26e71e0>
RE_SPLIT = <_sre.SRE_Pattern object at 0x7f62f0f69138>
SUPPORT_EMBED_IMAGES = True
embed_images(html)[source]

Embed images on local filesystem as data URI

>>> class Handler(BaseHandler):
...   def _generate(self, source=None): return source
>>> handler = Handler(None)
>>> html = '<img src="http://example.com/example.png"/>'
>>> print(handler.embed_images(html))
<img src="http://example.com/example.png"/>
>>> html = '<img src="tests/test.png"/>'
>>> print(handler.embed_images(html))  
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB...QmCC"/>
generate(markup=None)[source]

Generate HTML

>>> class Handler(BaseHandler):
...   def _generate(self, markup=None): return markup
>>> handler = Handler(None)
>>> print(handler.generate('foo "bar"'))
foo "bar"
>>> handler.options['smartypants'] = True
>>> print(handler.generate('foo "bar"'))
foo &#8220;bar&#8221;
generate_header(header=None)[source]

Generate header in text for writing back to the file

>>> class Handler(BaseHandler):
...   PREFIX_HEAD = 'foo '
...   PREFIX_END = 'bar'
...   HEADER_FMT = '--- %s: %s'
...   def _generate(self, source=None): pass
>>> handler = Handler(None)
>>> print(handler.generate_header({'title': 'foobar'}))
foo !b
--- title: foobar
bar

>>> print(handler.generate_header({'labels': ['foo', 'bar']}))
foo !b
--- labels: foo, bar
bar
generate_post()[source]

Generate dict for merging to post object of API

generate_title(title=None)[source]

Generate title for posting

>>> class Handler(BaseHandler):
...   def _generate(self, source=None): return source
>>> handler = Handler(None)
>>> print(handler.generate_title('foo "bar"'))
foo "bar"
>>> print(handler.generate_title('foo\nbar\n\n'))
foo bar
>>> handler.options['smartypants'] = True
>>> print(handler.generate_title('foo "bar"'))
foo &#8220;bar&#8221;
id_affix[source]

Return id_affix

The initial value is from self.options, and can be overriden by self.header.

Returns

  • None if it’s None.
  • value if value is not ‘’
  • first 4 digits of md5 of value if value is ‘’, and assign back to self.options. _generate method of Handler should write back to self.header.
>>> class Handler(BaseHandler):
...   def _generate(self, source=None): return source
>>> options = {
...   'id_affix': None,
...   }
>>> handler = Handler(None, options)
>>> print(repr(handler.id_affix))
None
>>> handler.options['id_affix'] = 'foobar'
>>> print(handler.id_affix)
foobar
>>> # auto generate an id affix from title
>>> handler.options['id_affix'] = ''
>>> handler.title = 'abc'
>>> print(handler.id_affix)
9001
>>> handler.header['id_affix'] = 'override-affix'
>>> print(handler.id_affix)
override-affix
markup[source]

Return markup with markup_prefix and markup_suffix

>>> class Handler(BaseHandler):
...   def _generate(self, source=None): return source
>>> options = {
...   'markup_prefix': 'the prefix\n',
...   'markup_suffix': '\nthe suffix',
...   }
>>> handler = Handler(None, options)
>>> handler.markup = 'content'
>>> print(handler.markup)
the prefix
content
the suffix
merge_header(header)[source]

Merge header

>>> class Handler(BaseHandler):
...   def _generate(self, source=None): return source
>>> handler = Handler(None)
>>> handler.merge_header({'id': 12345, 'bogus': 'blah'})
>>> print(handler.header['id'])
12345
>>> handler.modified
True
set_header(k, v)[source]

Set header

>>> class Handler(BaseHandler):
...   def _generate(self, source=None): return source
>>> handler = Handler(None)
>>> print(handler.header)
{}
>>> handler.modified
False
>>> handler.set_header('foo', 'bar')
>>> print(handler.header['foo'])
bar
>>> handler.modified
True
split_header_markup(source=None)[source]

Split source into header and markup parts

It also parses header into a dict.

update_source(header=None, markup=None, only_returned=False)[source]
write(forced=False)[source]

Write source back to file

bpy.handlers.html module

HTML handler simply takes the file content as its output, and assume it’s valid HTML, therefore the handler doesn’t edit or validate the content.

You can specify embed_images, for example:

handlers = {
  'HTML': {
    'options': {
      'embed_images': True,
    },
  },
}
class bpy.handlers.html.Handler(filename, options=None)[source]

Bases: bpy.handlers.base.BaseHandler

Handler for HTML

>>> handler = Handler(None)
>>> print(handler.generate_header({'title': 'foobar'}))
<!-- !b
title: foobar
-->
HEADER_FMT = u'%s: %s'
PREFIX_END = u'-->'
PREFIX_HEAD = u'<!-- '

bpy.handlers.mkd module

You can specify configuration for Python Markdown in brc.py or embed_images, for example:

handlers = {
  'Markdown': {
    'options': {
      'config': {
        'extensions': ['extension1', 'extension2'],
        'tab_length': 8,
      },
      'embed_images': True,
    },
  },
}
class bpy.handlers.mkd.Handler(filename, options=None)[source]

Bases: bpy.handlers.base.BaseHandler

Handler for Markdown markup language

>>> handler = Handler(None)
>>> print(handler.generate_header({'title': 'foobar'}))
<!-- !b
title: foobar
-->
HEADER_FMT = u'%s: %s'
PREFIX_END = u'-->'
PREFIX_HEAD = u'<!-- '

bpy.handlers.rst module

You can specify settings-overrides for reStructuredText in brc.py or the embed_images, for example:

handlers = {
  'reStructuredText': {
    'options': {
      'embed_images': True,
      'register_directives': {
        'dir_name': MyDir,
      },
      'register_roles': {
        'role_name': MyRole,
      },
      'settings_overrides': {
        'footnote_references': 'brackets',
      },
    },
  },
}

Custom Directives and Roles

For adding your own custom reStructuredText directives or roles, you can do it in brc.py with one of the following method:

  • by calling register functions of docutils directly,

  • by adding in b.py’s option as shown above, or

  • by using decorator of b.py, for example:

    from docutils.parsers.rst import Directive
    from bpy.handlers.rst import register_directive, register_role
    
    @register_directive('mydir')
    class MyDir(Directive):
      pass
    
    @register_role('myrole')
    def myrole(name, rawtext, text, lineno, inliner, options=None,
               content=None):
      pass
    
class bpy.handlers.rst.Handler(filename, options=None)[source]

Bases: bpy.handlers.base.BaseHandler

Handler for reStructuredText markup language

>>> handler = Handler(None)
>>> print(handler.generate_header({'title': 'foobar'}))
.. !b
   title: foobar
HEADER_FMT = u' %s: %s'
PREFIX_END = u''
PREFIX_HEAD = u'.. '
bpy.handlers.rst.register_directive(dir_name)[source]

For lazy guys

@register_directive(name)
class MyDirective(Directive):
  pass
bpy.handlers.rst.register_role(role_name)[source]

bpy.handlers.text module

The Text handler for plain text always escape HTML, and add <br/> if not pre_wrap.

You can specify the following options for plain text in brc.py, for example:

handlers = {
  'Text': {
    'options': {
      'pre_wrap': False
    },
  },
}

pre_wrap will wrap output in <pre/> tag.

class bpy.handlers.text.Handler(filename, options=None)[source]

Bases: bpy.handlers.base.BaseHandler

Handler for plain text

>>> handler = Handler(None)
>>> handler.markup = 'post <content>\n & something'
>>> print(handler.generate())
post &lt;content&gt;<br/>
 &amp; something
>>> handler.options['pre_wrap'] = True
>>> print(handler.generate())
<pre>post &lt;content&gt;
 &amp; something</pre>
>>> handler = Handler(None)
>>> print(handler.generate_header({'title': 'foobar'}))
!b
title: foobar
HEADER_FMT = u'%s: %s'
PREFIX_END = u''
PREFIX_HEAD = u''
SUPPORT_EMBED_IMAGES = False
generate_title(markup=None)[source]

Generate HTML from plain text

>>> handler = Handler(None)
>>> print(handler.generate_title('a < b\nc & d\n\nfoo'))
a &lt; b c &amp; d foo

Module contents

Markup handlers’ IDs and extensions:

ID extensions
AsciiDoc .asciidoc
HTML .html, .htm, .raw
Markdown .md, .mkd, .mkdn, .mkdown, .markdown
reStructuredText .rst
Text .txt, .text

Options

The general options are supported by all handlers, defined in bpy.handlers.base.BaseHandler, but they have to be specified per handler basis, the following sample code shows the options and their default value:

handlers = {
  '<MARKUP HANDLER ID>': {
    'options': {
      # prefix string to HTML ID to avoid conflict
      'id_affix': None,

      # string to prepend to actual markup
      'markup_prefix': '',

      # string to append to actual markup
      'markup_suffix': '',

      # use smartypant to process the output of markup processor
      'smartypants': False,

      # support image embedding via data URI scheme
      'embed_images': False,
    },
  },
}

id_affix

id_affix is used to avoid conflict across posts’ HTML element ID. It may be a prefix or suffix, depending on handler’s implementation and markup library’s support. It has three types of value:

  1. None: no affix to ID.
  2. non-empty string: the string is the affix.
  3. empty string: the affix is generated automatically.

Currently supported markup handler:

markup_prefix and markup_suffix

markup_prefix and markup_suffix can be useful for adding header and footer content for posts. Another useful case in reStructuredText is you can use it for setting up some directives, for example .. sectnum::, so you can ensure all posts have prefixing section number if in use conjunction with .. contents::.

smartypants

If smartypants is enabled, then all generated HTML from markup processor will be processed by smartypants library.

embed_images

Note

Only bpy.handlers.text does not support this option.

When this option is enabled, it looks for the src attribute of img tag in rendered HTML, see if there is a local files, excluding http, https, and data schemes, if found, it reads the file and embeds with Base64 encoded content.

For example, in reStructuredText:

.. image:: /path/to/test.png

Instead of

<img alt="/path/to/test.png" src="/path/to/test.png" />

It could be replaced with, if /path/to/test.png exists:

<img alt="/path/to/test.png" src="data:image/png;base64,..." />

If the image file can’t be found, a message will be printed out, the rendered image tag will be kept untouched.

Writing a custom handler

A sample handler sample_handler.py:

from bpy.handlers import base

class Handler(base.BaseHandler):
  PREFIX_HEAD = ''
  PREFIX_END = ''
  HEADER_FMT = '%s: %s'

  def _generate(self, markup=None):
    if markup is None:
      markup = self.markup

    html = do_process(markup)
    return html

And corresponding setting in brc.py:

import re

handlers = {
  'SampleHandler': {
    'match': re.compile(r'.*\.ext$'),
    'module': 'sample_handler',
  },
}
bpy.handlers.find_handler(filename)[source]