Skip to content

Commit

Permalink
Merge pull request #49 from sparsh-989/pandoc_support
Browse files Browse the repository at this point in the history
Added pandoc export
  • Loading branch information
mstimberg authored Jul 29, 2024
2 parents 552abd4 + 2881bbc commit 178eed8
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 5 deletions.
21 changes: 19 additions & 2 deletions brian2tools/mdexport/expander.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from sympy.printing import latex
from sympy.abc import *
from markdown_strings import *
from jinja2 import Template
from .template import templates
import numpy as np
import re
import inspect
Expand Down Expand Up @@ -284,7 +286,7 @@ def render_expression(self, expression, differential=False):
# to remove `$` (in most md compiler single $ is used)
return rend_exp[1:][:-1]

def create_md_string(self, net_dict):
def create_md_string(self, net_dict, template_name):
"""
Create markdown text by checking the standard dictionary and call
required expand functions and arrange the descriptions
Expand Down Expand Up @@ -373,6 +375,8 @@ def create_md_string(self, net_dict):
for connector in initializers_connectors
if connector['type'] == 'connect' and
connector['synapses'] == obj_mem['name']]
if obj_key == 'neurongroup' and current_order == 1:
obj_mem['template_name'] = template_name
run_string += ('- ' +
func_map[obj_key]['f'](obj_mem))

Expand Down Expand Up @@ -478,6 +482,7 @@ def expand_NeuronGroup(self, neurongrp):
neurongrp : dict
Standard dictionary of NeuronGroup
"""
template_name = neurongrp['template_name']
# start expanding
md_str = ''
# name and size
Expand Down Expand Up @@ -508,8 +513,18 @@ def expand_NeuronGroup(self, neurongrp):
self.check_plural(neurongrp['run_regularly']) + ': ' + endll)
for run_reg in neurongrp['run_regularly']:
md_str += self.expand_runregularly(run_reg)


# Create Jinja2 Template object
if template_name not in templates :
print(md_str)
return md_str
# Create Jinja2 Template object
template = Template(templates[template_name])
# # Render the template with the provided NeuronGroup dictionary
md_str = template.render(neurongrp=neurongrp)
print (md_str)
return md_str


def expand_SpikeSource(self, source):
"""
Expand Down Expand Up @@ -862,6 +877,7 @@ def expand_StateMonitor(self, statemon):
md_str += (', for member' +
self.check_plural(statemon['record']) +
': ' +

','.join([str(ind) for ind in statemon['record']]))
return md_str + endll

Expand Down Expand Up @@ -907,6 +923,7 @@ def expand_EventMonitor(self, eventmon):
','.join([str(ind) for ind in eventmon['record']]))
md_str += (' when event ' + bold(eventmon['event']) +
' is triggered')

return md_str + endll

def expand_PopulationRateMonitor(self, popratemon):
Expand Down
40 changes: 37 additions & 3 deletions brian2tools/mdexport/mdexporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from brian2tools.baseexport.device import BaseExporter
import os
import inspect
import subprocess
from .expander import *


Expand All @@ -13,7 +14,7 @@ class MdExporter(BaseExporter):
"""

def build(self, direct_call=True, debug=False, expander=None,
filename=None):
filename=None, additional_formats=None, template_type=None):
"""
Build the exporter
Expand All @@ -34,6 +35,15 @@ def build(self, direct_call=True, debug=False, expander=None,
If mentioned, the markdown text would be written in that
particular filename. When empty string '' is passed the user file
name would be taken
additional_formats : str or list of str or all
If user wants to have the output file in additional_formats they
can specify them under this variable and the options are pdf,
latex, html and all.
template_type : str
Based on your selected template, it will rendered otherwise
a default template will be used for rendering
"""
# buil_on_run = True but called build() directly
if self.build_on_run and direct_call:
Expand Down Expand Up @@ -70,7 +80,7 @@ def build(self, direct_call=True, debug=False, expander=None,
self.expander = MdExpander()

# start creating markdown descriptions using expander
self.md_text = self.expander.create_md_string(self.runs)
self.md_text = self.expander.create_md_string(self.runs, template_type)

# check output filename
if filename:
Expand All @@ -90,9 +100,33 @@ def build(self, direct_call=True, debug=False, expander=None,
print(self.md_text)
elif self.filename:
# start writing markdown text in file
md_file = open(self.filename + '.md', "w")
source_file = self.filename + ".md"
md_file = open(source_file, "w")
md_file.write(self.md_text)
md_file.close()

# Check if Pandoc is installed
try:
subprocess.check_call(["pandoc", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except FileNotFoundError:
raise Exception("Pandoc is not installed. Please install Pandoc and try again.")

formats_extensions = {'latex':'.tex', 'html':'.html', 'pdf':'.pdf'}
if isinstance(additional_formats, str):
if additional_formats == "all":
formats = ['latex', 'html', 'pdf']
else:
formats = [additional_formats]
else:
formats = additional_formats if additional_formats is not None else []
for format_name in formats:
filename = self.filename + formats_extensions[format_name]
try:
subprocess.run(["pandoc", "--from", "markdown", "--to", format_name, "-o", filename, source_file],
check=True)
print("Conversion complete! Files generated:", filename)
except subprocess.CalledProcessError as ex:
print(f"Could not generate format '{format_name}': {str(ex)}")
else:
pass # do nothing

Expand Down
54 changes: 54 additions & 0 deletions brian2tools/mdexport/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Define the Jinja2 template string
templates = {
'template_str' : """
## Network details
**Neuron population:**
- Group {{ neurongrp.name }}, consisting of {{ neurongrp.N }} neurons.
# Model dynamics
{% for key, eqn in neurongrp.equations.items() %}
- $\frac{d}{d t} {{ key }}$ = {{ eqn.expr }}{% if eqn.unit %} [{{ eqn.unit }}]{% endif %}
{% endfor %}
{% if neurongrp.user_method %}
The equations are integrated with the '{{ neurongrp.user_method }}' method.
{% endif %}
# Events (if present)
{% if 'events' in neurongrp %}
**Events:**
{% for event, details in neurongrp.events.items() %}
- If {{ details.threshold.code }}, a {{ event }} event is triggered and {{ details.reset.code }}.
{% endfor %}
{% endif %}
# Constants (if present)
{% if 'identifiers' in neurongrp %}
**Constants:**
{% for identifier, value in neurongrp.identifiers.items() %}
- {{ identifier }}: {{ value }}
{% endfor %}
{% endif %}
# Initial values (if present)
{% if 'initializer' in neurongrp and neurongrp['initializer'] %}
**Initial values:**
{% for initializer in neurongrp['initializer'] %}
- {{ initializer.variable }}: {{ initializer.value }}{% if initializer.unit %} [{{ initializer.unit }}]{% endif %}
{% endfor %}
{% endif %}
# Run regularly (if present)
{% if 'run_regularly' in neurongrp %}
**Run regularly:**
{% for run_reg in neurongrp['run_regularly'] %}
- {{ run_reg }}
{% endfor %}
{% endif %}
"""
}

0 comments on commit 178eed8

Please sign in to comment.