Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stringifying the terms of a definition list results in AttributeError #218

Closed
amine-aboufirass opened this issue Jul 13, 2022 · 7 comments
Closed
Labels

Comments

@amine-aboufirass
Copy link

I have the following markdown:

---
title: my title
author: bob marley
---

# Header {#identifier .class key=value}
 
Some text

::: {#special .glossary}
Term 1
: Definition 1

Term 2
: Definition 2
:::

I try to parse and stringify the individual terms and definitons of the definition lists with panflute as follows:

import panflute as pf

def action(elem, doc):
    if isinstance(elem, pf.Div):
        for definition_item in elem.content[0].content:
            # print(pf.stringify(definition_item.term))
            print(pf.stringify(definition_item.definitions[0]))


def debug():
    with open("definition-lists.md") as fs:
        markdown = fs.read()

    doc = pf.convert_text(markdown, standalone=True)
    doc.walk(action)

if __name__ == "__main__":
    debug()

It seems that the definition print out fine, but uncommenting line 6 in the python code results in the following error:

AttributeError: 'ListContainer' object has no attribute 'walk'

So I suspect it is not possible to stringify ListContainers like that.

How can I obtain the terms of my definition list using panflute? Thanks.

@amine-aboufirass
Copy link
Author

I came up with this solution:

import panflute as pf

def action(elem, doc):
    if isinstance(elem, pf.Div):
        for definition_item in elem.content[0].content:
            term = "".join(list(map(pf.stringify, definition_item.term)))
            print(term)
            print(pf.stringify(definition_item.definitions[0]))


def debug():
    with open("definition-lists.md") as fs:
        markdown = fs.read()

    doc = pf.convert_text(markdown, standalone=True)
    doc.walk(action)

if __name__ == "__main__":
    debug()

But I don't know if it's very good or robust. I feel like there should be a built-in way to "walk" through a ListContainer type....

@sergiocorreia
Copy link
Owner

I feel like there should be a built-in way to "walk" through a ListContainer type....

That makes sense, and might simplify some of the code

Still, I wonder if that will bring unexpected problems, so I need to think a bit more on this. I also think some things might be easier if we allow walk() to work top-to-bottom as needed.

BTW, unrelated but note that you are acting on a Div element and not on a DefinitionList object which makes the code a bit harder to read. For instance, the action function could be written as

   def action(elem, doc):
       if isinstance(elem, pf.DefinitionList):
           for item in elem.content:
               term = ''.join(pf.stringify(part) for part in item.term)
               definitions = '; '.join(pf.stringify(defn) for defn in  item.definitions)
               print(f'{term}: {definitions}')

@sergiocorreia
Copy link
Owner

Hi Amine,

Just added a new version https://github.com/sergiocorreia/panflute/releases/tag/v2.2.0 that should help you do what you want.

Besides adding walk() to lists as you suggested, walk() also supports an optional argument stop_if that takes a function that can be used to stop the tree traversal as needed.

This helps quite a bit when stringifying. I added a custom stringify code for definition lists which is hopefully close to what you want. Feel free to modify it (or to further improve stringify() and send a PR)

@amine-aboufirass
Copy link
Author

Hi @sergiocorreia that's awesome! I'll be sure to test it out as soon as possible.

With regards to the Div element, this is in fact intentional because I am writing code to parse through something like this:

:::{ .glossary }
function
: An operation which has an input and output

variable
: A symbol which can take on any value in a defined domain
:::

So I basically check whether the Div has a certain class before implementing what we discussed here. Not that that's super relevant, but now you know the context.

I'll repost once I give stop_if a shot...

@amine-aboufirass
Copy link
Author

Hi @sergiocorreia is there any way to install v2.2.0 using pip ? Or should I download the source code and install it locally?

@sergiocorreia
Copy link
Owner

Thanks for catching that. The new version should have been automatically published to pypi but was not due to a weird error (it was supposed to be published with Python 3.10 but the Github workflow understands 3.10=3.1 and there's no available Python 3.1 of course).

Should work not; let me know if not.

@amine-aboufirass
Copy link
Author

I was able to test this and it seems to work. Closing now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants