Skip to content

Commit

Permalink
Merge pull request #200 from jacobwhall/action-lists
Browse files Browse the repository at this point in the history
Fix #199  - Test and document list returning behavior for action functions
  • Loading branch information
sergiocorreia authored Nov 22, 2021
2 parents 281ddea + f449f29 commit d00acff
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 12 deletions.
9 changes: 6 additions & 3 deletions docs/source/code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,20 @@ Standard functions

- They are called as ``action(element, doc)`` so they must accept at
least two arguments.
- Additional arguments can be passed through the ``**kwargs** of
- Additional arguments can be passed through the ``**kwargs**`` of
``toJSONFilter`` and ``toJSONFilters``.
- They can return either an element, ``None``, or ``[]``.
- If they return ``None``, the document will keep the same document
- They can return either an element, a list, or ``None``.
- If they return ``None``, the document will keep the same element
as before (although it might have been modified).
- If they return another element, it will take the place of the
received element.
- If they return ``[]`` (an empty list), they will be deleted from the
document. Note that you can delete a row from a table or an item from
a list, but you cannot delete the caption from a table (you can
make it empty though).
- If the received element is a block or inline element, they may return
a list of elements of the same base class, which will take the place
of the received element.

"Batteries included" functions
******************************
Expand Down
2 changes: 1 addition & 1 deletion panflute/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ class Citation(Element):
"""
A single citation to a single work
:param id: citation key (e.g. the bibtex keyword)
:param id: citation key (e.g. the BibTeX keyword)
:type id: ``str``
:param mode: how will the citation appear ('NormalCitation' for the
default style, 'AuthorInText' to exclude parenthesis,
Expand Down
6 changes: 3 additions & 3 deletions panflute/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ def toJSONFilters(*args, **kwargs):


def toJSONFilter(*args, **kwargs):
r"""
Wapper for :func:`.run_filter`, which calls :func:`.run_filters`
"""
Wrapper for :func:`.run_filter`, which calls :func:`.run_filters`
toJSONFilter(action, prepare=None, finalize=None, input_stream=None, output_stream=None, \*\*kwargs)
Receive a Pandoc document from stdin, apply the *action* function to each element, and write it back to stdout.
Expand Down Expand Up @@ -215,7 +215,7 @@ def run_filters(actions,

def run_filter(action, *args, **kwargs):
"""
Wapper for :func:`.run_filters`
Wrapper for :func:`.run_filters`
Receive a Pandoc document from stdin, apply the *action* function to each element, and write it back to stdout.
Expand Down
11 changes: 6 additions & 5 deletions panflute/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@


class PandocVersion:
'''get runtime pandoc verison
'''
Get runtime Pandoc version
use PandocVersion().version for comparing versions
'''
Expand Down Expand Up @@ -214,7 +215,7 @@ def fenced_action(options, data, element, doc):

def stringify(element, newlines=True):
"""
Return the raw text version of an elements (and its children element).
Return the raw text version of an element (and its children elements).
Example:
Expand Down Expand Up @@ -351,7 +352,7 @@ def run_pandoc(text='', args=None, pandoc_path=None):
Low level function that calls Pandoc with (optionally)
some input text and/or arguments
:param str pandoc_path: If specified, use the pandoc at this path.
:param str pandoc_path: If specified, use the Pandoc at this path.
If None, default to that from PATH.
"""
if args is None:
Expand Down Expand Up @@ -416,7 +417,7 @@ def convert_text(text,
:type standalone: :class:`bool`
:param extra_args: extra arguments passed to Pandoc
:type extra_args: :class:`list`
:param str pandoc_path: If specified, use the pandoc at this path.
:param str pandoc_path: If specified, use the Pandoc at this path.
If None, default to that from PATH.
:rtype: :class:`list` | :class:`.Doc` | :class:`str`
Expand Down Expand Up @@ -605,7 +606,7 @@ def get_option(options=None, local_tag=None, doc=None, doc_tag=None, default=Non
although if a local or document tag returns None, then the next level down is used.
Also, if error_on_none=True and the final variable is None, then a ValueError will be raised
In this manner you can set global variables, which can be optionally overriden at a local level.
In this manner you can set global variables, which can be optionally overridden at a local level.
For example, the two files below show how to apply different styles to docx text:
**main.md:**
Expand Down
101 changes: 101 additions & 0 deletions tests/test_walk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""
Test how Element.walk() behaves with different return types of action functions
"""

import panflute as pf


def compare_docs(doc_a, doc_b):
doc_a_json = pf.convert_text(doc_a,
input_format='panflute',
output_format='json',
standalone=True)
doc_b_json = pf.convert_text(doc_b,
input_format='panflute',
output_format='json',
standalone=True)
return doc_a_json == doc_b_json


"""
Action functions to use in testing
"""


# Action that always returns None, changing nothing
def do_nothing(elem, doc):
return None


# Action that returns an empty list, deleting pf.Str elements
def remove_elem(elem, doc):
if isinstance(elem, pf.Str):
return []


# Action that returns a single inline element, writing over pf.Str elements
def inline_replace_elem(elem, doc):
if isinstance(elem, pf.Str):
return pf.Str("b")


# Action that returns a list of inline elements, writing over pf.Str elements
def inline_replace_list(elem, doc):
if isinstance(elem, pf.Str):
return [pf.Str("a"), pf.Space, pf.Str("b")]


# Action that returns a single inline element, writing over pf.Para elements
def block_replace_elem(elem, doc):
if isinstance(elem, pf.Para):
return pf.CodeBlock("b")


# Action that returns a list of block elements, writing over pf.Para elements
def block_replace_list(elem, doc):
if isinstance(elem, pf.Para):
return [pf.Para(pf.Str("a")), pf.Para(pf.Str("b"))]


"""
Test functions for above action functions
"""


def test_none():
in_doc = expected_doc = pf.Doc(pf.Para(pf.Str("a")))
in_doc.walk(do_nothing)
assert compare_docs(in_doc, expected_doc)


def test_empty_list():
in_doc = pf.Doc(pf.Para(pf.Str("a"), pf.Space))
in_doc.walk(remove_elem)
expected_doc = pf.Doc(pf.Para(pf.Space))
assert compare_docs(in_doc, expected_doc)

def test_inline_elem():
in_doc = pf.Doc(pf.Para(pf.Str("a")))
in_doc.walk(inline_replace_elem)
expected_doc = pf.Doc(pf.Para(pf.Str("b")))
assert compare_docs(in_doc, expected_doc)

def test_inline_list():
in_doc = pf.Doc(pf.Para(pf.Str("a")))
in_doc.walk(inline_replace_list)
expected_doc = pf.Doc(pf.Para(pf.Str("a"), pf.Space, pf.Str("b")))
assert compare_docs(in_doc, expected_doc)


def test_block_elem():
in_doc = pf.Doc(pf.Para(pf.Str("a")))
in_doc.walk(block_replace_elem)
expected_doc = pf.Doc(pf.CodeBlock("b"))
assert compare_docs(in_doc, expected_doc)


def test_block_list():
in_doc = pf.Doc(pf.Para(pf.Str("c")))
in_doc.walk(block_replace_list)
expected_doc = pf.Doc(pf.Para(pf.Str("a")), pf.Para(pf.Str("b")))
assert compare_docs(in_doc, expected_doc)

0 comments on commit d00acff

Please sign in to comment.