dendrotweaks 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. dendrotweaks/__init__.py +10 -0
  2. dendrotweaks/analysis/__init__.py +11 -0
  3. dendrotweaks/analysis/ephys_analysis.py +482 -0
  4. dendrotweaks/analysis/morphometric_analysis.py +106 -0
  5. dendrotweaks/membrane/__init__.py +6 -0
  6. dendrotweaks/membrane/default_mod/AMPA.mod +65 -0
  7. dendrotweaks/membrane/default_mod/AMPA_NMDA.mod +100 -0
  8. dendrotweaks/membrane/default_mod/CaDyn.mod +54 -0
  9. dendrotweaks/membrane/default_mod/GABAa.mod +65 -0
  10. dendrotweaks/membrane/default_mod/Leak.mod +27 -0
  11. dendrotweaks/membrane/default_mod/NMDA.mod +72 -0
  12. dendrotweaks/membrane/default_mod/vecstim.mod +76 -0
  13. dendrotweaks/membrane/default_templates/NEURON_template.py +354 -0
  14. dendrotweaks/membrane/default_templates/default.py +73 -0
  15. dendrotweaks/membrane/default_templates/standard_channel.mod +87 -0
  16. dendrotweaks/membrane/default_templates/template_jaxley.py +108 -0
  17. dendrotweaks/membrane/default_templates/template_jaxley_new.py +108 -0
  18. dendrotweaks/membrane/distributions.py +324 -0
  19. dendrotweaks/membrane/groups.py +103 -0
  20. dendrotweaks/membrane/io/__init__.py +11 -0
  21. dendrotweaks/membrane/io/ast.py +201 -0
  22. dendrotweaks/membrane/io/code_generators.py +312 -0
  23. dendrotweaks/membrane/io/converter.py +108 -0
  24. dendrotweaks/membrane/io/factories.py +144 -0
  25. dendrotweaks/membrane/io/grammar.py +417 -0
  26. dendrotweaks/membrane/io/loader.py +90 -0
  27. dendrotweaks/membrane/io/parser.py +499 -0
  28. dendrotweaks/membrane/io/reader.py +212 -0
  29. dendrotweaks/membrane/mechanisms.py +574 -0
  30. dendrotweaks/model.py +1916 -0
  31. dendrotweaks/model_io.py +75 -0
  32. dendrotweaks/morphology/__init__.py +5 -0
  33. dendrotweaks/morphology/domains.py +100 -0
  34. dendrotweaks/morphology/io/__init__.py +5 -0
  35. dendrotweaks/morphology/io/factories.py +212 -0
  36. dendrotweaks/morphology/io/reader.py +66 -0
  37. dendrotweaks/morphology/io/validation.py +212 -0
  38. dendrotweaks/morphology/point_trees.py +681 -0
  39. dendrotweaks/morphology/reduce/__init__.py +16 -0
  40. dendrotweaks/morphology/reduce/reduce.py +155 -0
  41. dendrotweaks/morphology/reduce/reduced_cylinder.py +129 -0
  42. dendrotweaks/morphology/sec_trees.py +1112 -0
  43. dendrotweaks/morphology/seg_trees.py +157 -0
  44. dendrotweaks/morphology/trees.py +567 -0
  45. dendrotweaks/path_manager.py +261 -0
  46. dendrotweaks/simulators.py +235 -0
  47. dendrotweaks/stimuli/__init__.py +3 -0
  48. dendrotweaks/stimuli/iclamps.py +73 -0
  49. dendrotweaks/stimuli/populations.py +265 -0
  50. dendrotweaks/stimuli/synapses.py +203 -0
  51. dendrotweaks/utils.py +239 -0
  52. dendrotweaks-0.3.1.dist-info/METADATA +70 -0
  53. dendrotweaks-0.3.1.dist-info/RECORD +56 -0
  54. dendrotweaks-0.3.1.dist-info/WHEEL +5 -0
  55. dendrotweaks-0.3.1.dist-info/licenses/LICENSE +674 -0
  56. dendrotweaks-0.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,201 @@
1
+ import pprint
2
+ from typing import List
3
+
4
+ ALLOWED_INDEPENDENT_VARS = ['cai', 'v']
5
+
6
+ # Assumptions:
7
+ # - Kinetic variables include the state variable name and
8
+ # the substrings inf or tau (e.g., minf, mtau). Order, case, and additional characters
9
+ # do not matter (e.g., mInf, tau_M are also valid).
10
+ # - The channel is either voltage or calcium dependent, and
11
+ # the independent variable is either v or cai.
12
+ # - Temperature adjustment coefficient is referred to as tadj and calculated as:
13
+ # tadj = q10^((celsius - temp)/10), where q10 is the temperature coefficient,
14
+ # temp is the reference temperature, and celsius is the current temperature.
15
+
16
+
17
+
18
+ class AbstracSyntaxTree():
19
+ """
20
+ A class to represent the abstract syntax tree of a .mod file.
21
+
22
+ Attributes
23
+ ----------
24
+ functions : List[Functional]
25
+ A list of Functional objects representing the FUNCTION blocks in the .mod file.
26
+ procedures : List[Functional]
27
+ A list of Functional objects representing the PROCEDURE blocks in the .mod file.
28
+ """
29
+
30
+ def __init__(self, ast_dict: dict):
31
+ # ast_dict = {k: v[0]
32
+ # if len(v) == 1 and k not in ['FUNCTION', 'PROCEDURE'] else v
33
+ # for k, v in ast_dict.items()}
34
+ self.functions = [Functional(func, has_return=True)
35
+ for func in ast_dict.get('FUNCTION', [])]
36
+ self.procedures = [Functional(proc, has_return=False)
37
+ for proc in ast_dict.get('PROCEDURE', [])]
38
+ self._ast = ast_dict
39
+
40
+ def __getitem__(self, key):
41
+ return self._ast[key]
42
+
43
+ def __setitem__(self, key, value):
44
+ self._ast[key] = value
45
+
46
+ def __repr__(self):
47
+ return pprint.pformat(self._ast, sort_dicts=False)
48
+
49
+ @property
50
+ def title(self):
51
+ return ''.join(self['TITLE']).strip()
52
+
53
+ @property
54
+ def comment(self):
55
+ return ''.join(self['COMMENT']).strip()
56
+
57
+ # NEURON block
58
+ @property
59
+ def suffix(self):
60
+ if self['NEURON'] is not None:
61
+ return self['NEURON']['suffix']
62
+
63
+ @property
64
+ def ion(self):
65
+ if self['NEURON'].get('useion'):
66
+ ions = [ion['ion']
67
+ for ion in self['NEURON']['useion'] if ion.get('write', '')]
68
+ if len(ions) == 1:
69
+ return ions[0]
70
+ elif len(ions) == 0:
71
+ return None
72
+ else:
73
+ raise Exception('Multiple ions not supported')
74
+ else:
75
+ return None
76
+
77
+ # PARAMETER block
78
+ @property
79
+ def params(self):
80
+ """
81
+ Returns a dictionary of the parameters in the PARAMETER block.
82
+ """
83
+ return {param['name']: param['value'] for param in self['PARAMETER']}
84
+
85
+ @property
86
+ def range_params(self):
87
+ """
88
+ Returns a dictionary of the range parameters in the PARAMETER block.
89
+ """
90
+ return {k:v for k, v in self.params.items()
91
+ if k in self['NEURON']['range']}
92
+
93
+
94
+ # ASSIGNED block
95
+ @property
96
+ def assigned_vars(self):
97
+ """
98
+ Returns a list of the assigned variables in the ASSIGNED block.
99
+ """
100
+ return [assigned['name'] for assigned in self['ASSIGNED']]
101
+
102
+ @property
103
+ def independent_var_name(self):
104
+ """
105
+ Returns the name of the independent variable.
106
+ Prefers 'cai' over 'v' if both are present.
107
+ """
108
+ independent_vars = [var for var in self.assigned_vars
109
+ if any(indep_var in var.lower()
110
+ for indep_var in ALLOWED_INDEPENDENT_VARS)]
111
+ if 'cai' in independent_vars:
112
+ return 'cai'
113
+ elif 'v' in independent_vars:
114
+ return 'v'
115
+ raise Exception('Independent variable not found')
116
+
117
+ def is_voltage_dependent(self):
118
+ """
119
+ Returns True if the mechanism is voltage dependent.
120
+ """
121
+ for var in self.assigned_vars:
122
+ if 'v' in var.lower():
123
+ return True
124
+ return False
125
+
126
+ def is_ca_dependent(self):
127
+ """
128
+ Returns True if the mechanism is calcium dependent.
129
+ """
130
+ for var in self.assigned_vars:
131
+ if 'cai' in var.lower():
132
+ return True
133
+ return False
134
+
135
+ # STATE block
136
+ @property
137
+ def state_vars(self):
138
+ """
139
+ Returns a dictionary of the state variables in the STATE block.
140
+ """
141
+ return self['STATE']
142
+
143
+
144
+ class Functional():
145
+ """
146
+ A class to represent abstract syntax tree of a
147
+ FUNCTION or PROCEDURE block in a .mod file.
148
+
149
+ Attributes
150
+ ----------
151
+ has_return : bool
152
+ Whether the block has a return statement (is a FUNCTION block)
153
+ or not (is a PROCEDURE block).
154
+ """
155
+
156
+ def __init__(self, func_ast, has_return=True):
157
+ self._ast = func_ast
158
+ self.has_return = has_return
159
+
160
+ def __getitem__(self, key):
161
+ return self._ast[key]
162
+
163
+ def get(self, key, default=None):
164
+ return self._ast.get(key, default)
165
+
166
+ def __setitem__(self, key, value):
167
+ self._ast[key] = value
168
+
169
+ def __repr__(self):
170
+ return pprint.pformat(self._ast, sort_dicts=False)
171
+
172
+ # Signature\
173
+ @property
174
+ def name(self):
175
+ return self['signature']['name']
176
+
177
+ @name.setter
178
+ def name(self, value):
179
+ self['signature']['name'] = value
180
+
181
+ @property
182
+ def params(self):
183
+ return [param['name'] for param in self['signature'].get('params', [])]
184
+
185
+ # Locals
186
+ @property
187
+ def local_vars(self):
188
+ local_vars = []
189
+ if self.has_return:
190
+ local_vars.append(self['signature']['name'])
191
+ local_vars.extend([arg['name'] for arg in self['signature'].get('args', [])])
192
+ local_vars.extend(self.get('locals', []))
193
+ return local_vars
194
+
195
+ @property
196
+ def signature(self):
197
+ return self['signature']
198
+
199
+ @property
200
+ def statements(self):
201
+ return self['statements']
@@ -0,0 +1,312 @@
1
+ import re
2
+ import os
3
+ from jinja2 import Template
4
+
5
+ from abc import ABC, abstractmethod
6
+ from jinja2 import Environment, FileSystemLoader
7
+ from dendrotweaks.utils import write_file
8
+
9
+ # Configure the Jinja2 environment
10
+ # env = Environment(
11
+ # loader=FileSystemLoader('static/data/templates'), # Load templates from the 'templates' directory
12
+ # trim_blocks=False, # Trim newlines after Jinja blocks
13
+ # lstrip_blocks=False, # Strip leading whitespace from Jinja blocks
14
+ # )
15
+
16
+ EQUILIBRIUM_POTENTIALS = {
17
+ 'na': 60,
18
+ 'k': -80,
19
+ 'ca': 140
20
+ }
21
+
22
+ class CodeGenerator(ABC):
23
+
24
+ @abstractmethod
25
+ def generate(self, ast, path_to_template):
26
+ pass
27
+
28
+ def write_file(self, path_to_file):
29
+ write_file(self.content, path_to_file)
30
+
31
+
32
+ class PythonCodeGenerator(CodeGenerator):
33
+ """ A class to generate Python code from an AST using a Jinja2 template. """
34
+
35
+ def __init__(self):
36
+ self.content = None
37
+
38
+ # MAIN METHOD
39
+
40
+ def generate(self, ast, path_to_template):
41
+ """
42
+ Generate a Python class from the AST using a Jinja2 template.
43
+
44
+ Parameters
45
+ ----------
46
+ ast : dict
47
+ The AST representation of the channel
48
+ path_to_template : str
49
+ The path to the Jinja2 template file
50
+
51
+ Returns
52
+ -------
53
+ str
54
+ The Python code generated from the AST
55
+ """
56
+
57
+ # Read the template file
58
+ with open(path_to_template, 'r') as file:
59
+ template_string = file.read()
60
+
61
+ # # Create a Jinja2 template from the string
62
+ template = Template(template_string)
63
+ # template = env.get_template(self.path_to_template)
64
+
65
+ # Define the variables for the template
66
+ variables = {
67
+ 'title': ast.title,
68
+ # 'comment': ast.comment,
69
+ 'class_name': ast.suffix,
70
+ 'suffix': ast.suffix,
71
+ 'ion': ast.ion,
72
+ 'independent_var_name': ast.independent_var_name,
73
+ 'channel_params': ast.params,
74
+ 'range_params': ast.range_params,
75
+ 'state_vars': ast.state_vars,
76
+ 'functions': self._generate_functions(ast),
77
+ 'procedures': self._generate_procedures(ast),
78
+ 'procedure_calls': self._generate_procedure_calls(ast),
79
+ 'E_ion': EQUILIBRIUM_POTENTIALS.get(ast.ion, None)
80
+ }
81
+
82
+ # Render the template with the variables
83
+ content = template.render(variables)
84
+
85
+ if re.search(r'\bjnp\b', template_string):
86
+ content = content.replace('np', 'jnp')
87
+
88
+ self.content = content
89
+
90
+
91
+ # HELPER METHODS
92
+
93
+ def _generate_functions(self, ast, indent=8):
94
+ functions = []
95
+
96
+ for function in ast.functions:
97
+ # Generate the signature
98
+ signature_str = self._generate_signature(function.signature)
99
+
100
+ # Generate the body
101
+ body_str = self._generate_body(function.statements)
102
+ for name in [function.name for function in ast.functions if function != function]:
103
+ body_str = re.sub(r'\b' + re.escape(name) + r'\b', f"self.{name}", body_str)
104
+ body_str = re.sub(r'\b' + re.escape('tadj') + r'\b', f"self.tadj", body_str)
105
+ body_str = re.sub(r'\b' + re.escape('celsius') + r'\b', f"self.temperature", body_str)
106
+ body_str += f"return {function.name}"
107
+ body_str = '\n'.join(' ' * indent + line
108
+ for line in body_str.splitlines())
109
+
110
+ # Find the parameters that are used in the body
111
+ params = [param for param in ast.params
112
+ if param not in function.local_vars
113
+ and param not in function.params
114
+ and re.search(r'\b' + re.escape(param) + r'\b', body_str)]
115
+
116
+ functions.append({
117
+ 'signature': signature_str,
118
+ 'params': params,
119
+ 'body': body_str.strip()
120
+ })
121
+
122
+ return functions
123
+
124
+ def _generate_procedures(self, ast, indent=8):
125
+
126
+ if len(ast.procedures) != 1:
127
+ raise ValueError("Only one procedure is supported")
128
+ ast.procedures[0].name = 'compute_kinetic_variables'
129
+
130
+ procedures = []
131
+
132
+ for procedure in ast.procedures:
133
+ # Generate the signature
134
+ signature_str = self._generate_signature(procedure.signature,
135
+ is_method=True,
136
+ extra_params=['celsius'])
137
+
138
+ # Generate the body
139
+ body_str = self._generate_body(procedure.statements)
140
+ for name in [function.name for function in ast.functions]:
141
+ body_str = re.sub(r'\b' + re.escape(name) + r'\b', f"self.{name}", body_str)
142
+ body_str = re.sub(r'\b' + re.escape('tadj') + r'\b', f"self.tadj", body_str)
143
+ body_str = re.sub(r'\b' + re.escape('celsius') + r'\b', f"self.temperature", body_str)
144
+ body_str += 'return ' + ', '.join([f"{state_var}Inf, {state_var}Tau"
145
+ for state_var in ast.state_vars])
146
+ body_str = '\n'.join(' ' * indent + line
147
+ for line in body_str.splitlines())
148
+
149
+ # Find the parameters that are used in the body
150
+ params = [param for param in ast.params
151
+ if param not in procedure.local_vars
152
+ and re.search(r'\b' + re.escape(param) + r'\b', body_str)]
153
+
154
+ procedures.append({
155
+ 'signature': signature_str,
156
+ 'params': params,
157
+ 'body': body_str.strip()
158
+ })
159
+
160
+ return procedures
161
+
162
+ def _generate_signature(self, signature, is_method=True, extra_params=None):
163
+ """
164
+ Generate the signature string for a function using a Jinja2 template.
165
+ The function AST representation is used to retrieve the function name
166
+ and parameters:
167
+ >>> def f_name(self, arg1, arg2, ...):
168
+
169
+ Parameters
170
+ ----------
171
+ signature : dict
172
+ The function signature as an AST dictionary
173
+ is_method : bool
174
+ Whether the function is a class method or not
175
+ """
176
+ signature_template = (
177
+ "def {{ name }}({% if params %}{{ params | join(', ') }}{% endif %}):"
178
+ )
179
+ template = Template(signature_template)
180
+ name = signature['name']
181
+ params = [param['name'] for param in signature.get('params', [])]
182
+ if is_method:
183
+ params = ['self'] + params
184
+
185
+ return template.render(name=name, params=params)
186
+
187
+ def _generate_body(self, statements, indent=12, skip_vars=['tadj']):
188
+ python_code = ""
189
+ # Add statements
190
+ for statement in statements:
191
+ # If the statement is an if-else statement
192
+ if statement.get('condition', False):
193
+ python_code += self._generate_conditionals(statement)
194
+ else:
195
+ if statement['assigned_var'] in skip_vars:
196
+ continue
197
+ python_code += (f"{statement['assigned_var']} = {statement['expression']}\n")
198
+
199
+ return python_code
200
+
201
+ def _generate_conditionals(self, statement):
202
+ """
203
+ Generate the conditional statement for an if-else block using a Jinja2 template.
204
+ """
205
+ condition = statement['condition']
206
+ if_statements = statement['if_statements']
207
+ else_statements = statement.get('else_statements', [])
208
+ else_statements = {statement['assigned_var']: statement['expression'] for statement in else_statements}
209
+
210
+ conditional_code = ""
211
+ for if_statement in statement['if_statements']:
212
+ # Default to variable name if not in else_expressions
213
+ else_statement = else_statements.get(
214
+ if_statement['assigned_var'],
215
+ if_statement["assigned_var"]
216
+ )
217
+
218
+ # Use a Jinja2 template to generate the conditional code
219
+ conditional_template = (
220
+ "conditions = [{{ condition }}, ~({{ condition }})]"
221
+ "\nchoices = [{{ if_statement }}, {{ else_statement }}]"
222
+ "\n{{ assigned_var }} = np.select(conditions, choices)"
223
+ )
224
+ template = Template(conditional_template)
225
+ conditional_code += template.render(
226
+ condition=condition,
227
+ if_statement=if_statement['expression'],
228
+ else_statement=else_statement,
229
+ assigned_var=if_statement['assigned_var']
230
+ )
231
+ conditional_code += "\n" # Add a newline between blocks
232
+
233
+ return conditional_code
234
+
235
+ def _generate_procedure_calls(self, ast):
236
+
237
+ for procedure in ast.procedures:
238
+
239
+ name = procedure.signature['name']
240
+ params = [param['name'] for param in procedure.signature.get('params', [])]
241
+ state_vars = list(ast.state_vars.keys())
242
+
243
+ procedure_call_template = """{%- for state_var in state_vars -%}
244
+ {{ state_var }}Inf, {{ state_var }}Tau{% if not loop.last %}, {% endif -%}
245
+ {% endfor %} = self.{{ name }}({% if params %}{{ params | join(', ') }}{% endif %})
246
+ """
247
+ template = Template(procedure_call_template.strip())
248
+
249
+ return template.render(
250
+ name=name,
251
+ params=params,
252
+ state_vars=state_vars
253
+ )
254
+
255
+
256
+
257
+ class NMODLCodeGenerator(CodeGenerator):
258
+ """ A class to generate NMODL code from a StandardIonChannel"""
259
+
260
+ def __init__(self):
261
+ self.content = None
262
+
263
+ def generate(self, channel,
264
+ path_to_template: str) -> None:
265
+ """
266
+ Generate NMODL code for a standardized ion channel
267
+ using a Jinja2 template.
268
+
269
+ Parameters
270
+ ----------
271
+ channel : StandardIonChannel
272
+ The standardized ion channel.
273
+ path_to_template : str
274
+ The path to the Jinja2 template file.
275
+ """
276
+
277
+ # Read the template file
278
+ with open(path_to_template, 'r') as file:
279
+ template_string = file.read()
280
+
281
+ # Create a Jinja2 template from the string
282
+ template = Template(template_string)
283
+
284
+ def get_unit(param):
285
+ if param.startswith('vhalf_'): return 'mV'
286
+ elif param.startswith('sigma_'): return 'mV'
287
+ elif param.startswith('k_'): return '1/ms'
288
+ elif param.startswith('delta_'): return '1'
289
+ elif param.startswith('tau0_'): return 'ms'
290
+ elif param.startswith('temp'): return 'degC'
291
+ elif param.startswith('q10'): return '1'
292
+ elif param.startswith('gbar'): return 'S/cm2'
293
+ else: return '1'
294
+
295
+ # Define the variables for the template
296
+ variables = {
297
+ 'suffix': channel.name,
298
+ 'ion': channel.ion,
299
+ 'range_params': [
300
+ (param, channel.params[param], get_unit(param))
301
+ for param in channel.params
302
+ ],
303
+ 'state_vars': {
304
+ var: params['power'] for var, params in channel._state_powers.items()
305
+ },
306
+ }
307
+
308
+ # Render the template with the variables
309
+ content = template.render(variables)
310
+
311
+ self.content = content
312
+ return content
@@ -0,0 +1,108 @@
1
+ from dendrotweaks.membrane.io.reader import MODFileReader
2
+ from dendrotweaks.membrane.io.parser import MODFileParser
3
+ from dendrotweaks.membrane.io.code_generators import PythonCodeGenerator
4
+
5
+ class MODFileConverter():
6
+ """
7
+ Converts a MOD file to a Python file.
8
+
9
+ Attributes
10
+ ----------
11
+ reader : MODFileReader
12
+ The MOD file reader.
13
+ parser : MODFileParser
14
+ The MOD file parser.
15
+ generator : PythonCodeGenerator
16
+ The Python code generator.
17
+ """
18
+
19
+ def __init__(self):
20
+ self.reader = MODFileReader()
21
+ self.parser = MODFileParser()
22
+ self.generator = PythonCodeGenerator()
23
+
24
+ @property
25
+ def mod_content(self):
26
+ """
27
+ The content of the MOD file.
28
+ """
29
+ return self.reader.content
30
+
31
+ @property
32
+ def blocks(self):
33
+ """
34
+ The blocks of the MOD file corresponding to the
35
+ NMODL blocks e.g. NEURON, PARAMETER, ASSIGNED, etc.
36
+ """
37
+ return self.reader.blocks
38
+
39
+ @property
40
+ def ast(self):
41
+ """
42
+ The abstract syntax tree of the MOD file.
43
+ """
44
+ return self.parser.ast
45
+
46
+ @property
47
+ def python_content(self):
48
+ """
49
+ The content of the generated Python file.
50
+ """
51
+ return self.code_generator.content
52
+
53
+ # def convert(self, path_to_mod, path_to_python, path_to_template):
54
+ # """ Converts a mod file to a python file.
55
+
56
+ # Parameters
57
+ # ----------
58
+ # path_to_mod : str
59
+ # The path to the mod file.
60
+ # path_to_python : str
61
+ # The path to the python file.
62
+ # path_to_template : str
63
+ # The path to the template file.
64
+ # """
65
+
66
+ # self.read_file(path_to_mod) # generates self.mod_content
67
+ # self.preprocess() # generates self.blocks
68
+ # self.parse() # generates self.ast
69
+ # self.generate_python(path_to_template) # generates self.python_content
70
+ # self.write_file(path_to_python) # writes self.python_content to path_to_python
71
+
72
+ def convert(self, path_to_mod_file: str,
73
+ path_to_python_file: str,
74
+ path_to_python_template: str,
75
+ path_to_json_file:str = None,
76
+ verbose: bool = False) -> None:
77
+ """ Converts a MOD file to a Python file.
78
+
79
+ Parameters
80
+ ----------
81
+ path_to_mod : str
82
+ The path to the original MOD file.
83
+ path_to_python : str
84
+ The path to the output Python file.
85
+ path_to_template : str
86
+ The path to the jinja2 template file.
87
+ path_to_json : str, optional
88
+ The path to the json file to write the AST.
89
+ verbose : bool, optional
90
+ Whether to print the progress of the conversion.
91
+ """
92
+
93
+ if verbose: print(f"READING")
94
+ self.reader.read_file(path_to_mod_file)
95
+ self.reader.preprocess()
96
+ blocks = self.reader.get_blocks(verbose)
97
+
98
+ if verbose: print(f"\nPARSING")
99
+ self.parser.parse(blocks, verbose)
100
+ self.parser.postprocess()
101
+ ast = self.parser.get_ast()
102
+
103
+ if path_to_json_file:
104
+ self.parser.write_file(path_to_json_file)
105
+
106
+ if verbose: print(f"\nGENERATING")
107
+ self.generator.generate(ast, path_to_python_template)
108
+ self.generator.write_file(path_to_python_file)