jankatins / knitpy

knitpy: Elegant, flexible and fast dynamic report generation with python
https://github.com/jankatins/knitpy
Other
368 stars 29 forks source link

support accessing variables in scope while using Knitpy().render(...) #26

Closed thatcher closed 3 years ago

thatcher commented 9 years ago

Based on the knitr api I thought the following pattern would work to be able to 'pass' data to the report template:

from knitpy.knitpy import Knitpy

report = Knitpy()
animal_sounds = {
   ‘pig’: ‘Oink, oink.’
}
report.render(‘farm_animals.pymd’, output=’pdf’)

assuming farm_animals.pymd looks like this (triple tick is escaped just to display correctly in this issue):

#Farm Animals
\```{python}
for key, value in animal_sounds.items():
    print “This is a %s, it says ‘%s’.” % (key, value)
\```

The end result being an error in the generated output:

NameError: name 'animal_sounds' is not defined

So I'm not sure if this is expected behavior? My expectation is based on this thread for knitr:

https://github.com/yihui/knitr/issues/567

If a report should not be expected to have access to the scope its rendered in, what is the desired way to pass arguments to a report template pymd during rendering?

Thanks, Thatcher

jankatins commented 9 years ago

This is actually one of the behaviours which won't work, as the call to render and the actual context for the document are in different python processes due to using a ipython kernel to "execute" the document.

So it's definitive not supported right now. I updated the title to reflect this.

A workaround could be to dump the data structure (pickle or json), include that before the document in an invisible python block and deserialize it there. The other workaround would be to write it to the filesystem and load it there.

Re parametririzing: I think I would prefer something along these lines

doc = """ ... {parameter}....""
Knitpy().render(doc.format(parameter="something"))
thatcher commented 9 years ago

Ok Im following you, in this case I do have a report template that is built with the goal of passing some data dynamically, which could be a single file name from which to deserialize the data or a python dictionary. The workarounds you illustrated would address these cases so for now I'll basically do something to that effect.

Many template apis allow an optional 'context' to be passed to 'render' which in this case would either be made available to the IPython context or would apply one the methods you described to inject it into the pymd as a hidden code block. Though the end user could programatically do the formatting it might be nice for api to support it directly since dynamic reports sort of imply dynamic context. Maybe another optional keyword argument to render?

Knitpy().render(filename, output='all', context=my_report_data)

It would the details remain opaque to the user. A similar option might be useful at the command line?

Just thinking out loud. I normally used knitr in the past for papers where I could hard code paths to my data. In this case it is a report template so a built-in way to supply context would be great.