executablebooks / MyST-Parser

An extended commonmark compliant parser, with bridges to docutils/sphinx
https://myst-parser.readthedocs.io
MIT License
759 stars 196 forks source link

Can functions be used in MyST-Parser (using Jinja2)? #338

Open firasm opened 3 years ago

firasm commented 3 years ago

Is your feature request related to a problem? Please describe.

Is there a way to run code and use myst substitutions (via Jinja) to plug in the result in docs?

Here is a minimal file I'm trying to render:

---
substitutions:
    a: 100*2
    b: 2
---

Here are the variables: {{a}} and {{b}}.

What I get for this is:

Here are the variables: 100*2 and 2.

Describe the solution you'd like

What I want is:

Here are the variables: 200 and 2.

If there was a way to run arbitrary python code (random numbers, complex functions, sin/cos), that would be the dream. I am also happy for the python code/function to be in a separate file if that makes this easier.

Additional context

I am trying to create a problem bank with randomized questions using MyST as my base language.

I am now having the feeling I should have opened this issue in the Jinja repo instead...

choldgraf commented 3 years ago

I don't think this is possible (though I agree maybe the Jinja folks would have some ideas?). I think it's a really interesting idea though!

firasm commented 3 years ago

I'll try that - hunting around the Jinja documentation, interestingly, I think I can do simple math:

- {{b}} x {{c}} = {{b*c}}
- {{b}} + {{c}} = {{b+c}}
- {{b}} / {{c}} = {{b / c}}

Which produces:

  • 2 x 100 = 200
  • 2 + 100 = 102
  • 2 / 100 = 0.02

Which is cool. I'll open an issue there to see if they have any suggestions for arbitrary python functions

firasm commented 3 years ago

Good news: It looks like this is possible in Jinja as per this SO answer:

from jinja2 import Template

def custom_function(a):
    return a.replace('o', 'ay')

template = Template('Hey, my name is {{ custom_function(first_name) }} {{ func2(last_name) }}')
template.globals['custom_function'] = custom_function

Bad news: The only question that remains is what the equivalent way is in MyST-Parser. I am hopeful but am afraid I'm at the end of my python chops - maybe @chrisjsewell has some ideas?

I've set up a repo here with a minimal example in case it helps...

andersk commented 3 years ago

Interestingly, this does work:

---
substitutions:
    a: '{{100*2}}'
    b: 2
---

Here are the variables: {{a}} and {{b}}.

Here are the variables: 200 and 2.

but not this:

---
substitutions:
    a: {{100*2}}
    b: 2
---

Here are the variables: {{a}} and {{b}}.
Exception occurred:
yaml.constructor.ConstructorError: while constructing a mapping
  in "<unicode string>", line 2, column 8:
        a: {{100*2}}
           ^
found unhashable key
  in "<unicode string>", line 2, column 9:
        a: {{100*2}}
            ^