md_to_code updated to generate tests and human readable example code from markdown scripts
This commit is contained in:
parent
14d6f5a7fb
commit
360683a633
|
@ -0,0 +1,98 @@
|
|||
```python
|
||||
import gaspype as gp
|
||||
from gaspype import R, F
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
fuel_utilization = 0.90
|
||||
air_utilization = 0.5
|
||||
t = 800 + 273.15 #K
|
||||
p = 1e5 #Pa
|
||||
|
||||
fs = gp.fluid_system('H2, H2O, O2, CH4, CO, CO2')
|
||||
feed_fuel = gp.fluid({'CH4': 1, 'H2O': 0.1}, fs)
|
||||
|
||||
o2_full_conv = np.sum(gp.elements(feed_fuel)[['H', 'C' ,'O']] * [1/4, 1, -1/2])
|
||||
|
||||
feed_air = gp.fluid({'O2': 1, 'N2': 4}) * o2_full_conv / air_utilization
|
||||
|
||||
conversion = np.linspace(0, fuel_utilization, 32)
|
||||
perm_oxygen = o2_full_conv * conversion * gp.fluid({'O2': 1})
|
||||
|
||||
fuel_side = gp.equilibrium(feed_fuel + perm_oxygen, t, p)
|
||||
air_side = gp.equilibrium(feed_air - perm_oxygen, t, p)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
#Plot compositions on fuel and air side
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_xlabel("Conversion")
|
||||
ax.set_ylabel("Molar fraction")
|
||||
ax.plot(conversion, fuel_side.get_x(), '-')
|
||||
ax.legend(fuel_side.species)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_xlabel("Conversion")
|
||||
ax.set_ylabel("Molar fraction")
|
||||
ax.plot(conversion, air_side.get_x(), '-')
|
||||
ax.legend(air_side.species)
|
||||
```
|
||||
|
||||
```python
|
||||
o2_fuel_side = gp.oxygen_partial_pressure(fuel_side, t, p)
|
||||
o2_air_side = air_side.get_x('O2') * p
|
||||
```
|
||||
|
||||
```python
|
||||
#Plot oxygen partial pressure
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_xlabel("Conversion")
|
||||
ax.set_ylabel("Oxygen partial pressure / Pa")
|
||||
ax.set_yscale('log')
|
||||
ax.plot(conversion, np.stack([o2_fuel_side, o2_air_side], axis=1), '-')
|
||||
ax.legend(['o2_fuel_side', 'o2_air_side'])
|
||||
```
|
||||
|
||||
```python
|
||||
z_O2 = 4
|
||||
nernst_voltage = R*t / (z_O2*F) * np.log(o2_air_side/o2_fuel_side)
|
||||
```
|
||||
|
||||
```python
|
||||
#Plot voltage potential
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_xlabel("Conversion")
|
||||
ax.set_ylabel("Voltage / V")
|
||||
ax.plot(conversion, nernst_voltage, '-')
|
||||
print(np.min(nernst_voltage))
|
||||
```
|
||||
|
||||
```python
|
||||
cell_voltage = 0.77 #V
|
||||
ASR = 0.2 #Ohm*cm²
|
||||
|
||||
node_current = (nernst_voltage - cell_voltage) / ASR #mA/cm² (Current density at each node)
|
||||
|
||||
current = (node_current[1:] + node_current[:-1]) / 2 #mA/cm² (Average current density between the nodes)
|
||||
|
||||
dz = 1/current / np.sum(1/current) #Relative distance between each node
|
||||
|
||||
terminal_current = np.sum(current * dz) #mA/cm² (Total cell current per cell area)
|
||||
|
||||
print(f'Terminal current: {terminal_current:.2f} A/cm²')
|
||||
```
|
||||
|
||||
```python
|
||||
#Plot current density
|
||||
z_position = np.concatenate([[0], np.cumsum(dz)]) #Relative position of each node
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_xlabel("Relative cell position")
|
||||
ax.set_ylabel("Current density / A/cm²")
|
||||
ax.plot(z_position, node_current, '-')
|
||||
```
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
|
||||
|
||||
import re
|
||||
from typing import Generator, Iterable, Literal
|
||||
from dataclasses import dataclass
|
||||
import sys
|
||||
|
||||
@dataclass
|
||||
class markdown_segment:
|
||||
code_block: bool
|
||||
language: str
|
||||
text: str
|
||||
|
||||
|
||||
def convert_to(target_format: str, md_filename: str, out_filename: str, language: str = 'python'):
|
||||
with open(md_filename, "r") as f_in, open(out_filename, "w") as f_out:
|
||||
segments = segment_markdown(f_in)
|
||||
|
||||
if target_format == 'test':
|
||||
f_out.write('\n'.join(segments_to_test(segments, language)))
|
||||
elif target_format == 'script':
|
||||
f_out.write('\n'.join(segments_to_script(segments, language)))
|
||||
elif target_format == 'striped_markdown':
|
||||
f_out.write('\n'.join(segments_to_striped_markdown(segments, language)))
|
||||
else:
|
||||
raise ValueError('Unknown target format')
|
||||
|
||||
|
||||
def segment_markdown(markdown_file: Iterable[str]) -> Generator[markdown_segment, None, None]:
|
||||
regex = re.compile(r"(?:^```\s*(?P<language>(?:\w|-)*)$)", re.MULTILINE)
|
||||
|
||||
block_language: str = ''
|
||||
code_block = False
|
||||
line_buffer: list[str] = []
|
||||
|
||||
for line in markdown_file:
|
||||
match = regex.match(line)
|
||||
if match:
|
||||
if line_buffer:
|
||||
yield markdown_segment(code_block, block_language, ''.join(line_buffer))
|
||||
line_buffer.clear()
|
||||
block_language = match.group('language')
|
||||
code_block = not code_block
|
||||
else:
|
||||
line_buffer.append(line)
|
||||
|
||||
if line_buffer:
|
||||
yield markdown_segment(code_block, block_language, '\n'.join(line_buffer))
|
||||
|
||||
|
||||
def segments_to_script(segments: Iterable[markdown_segment], test_language: str = "python") -> Generator[str, None, None]:
|
||||
for segment in segments:
|
||||
if segment.code_block:
|
||||
if segment.language == test_language:
|
||||
yield segment.text
|
||||
|
||||
else:
|
||||
for line in segment.text.splitlines():
|
||||
yield '# | ' + line
|
||||
yield ''
|
||||
|
||||
else:
|
||||
for line in segment.text.strip(' \n').splitlines():
|
||||
yield '# ' + line
|
||||
yield ''
|
||||
|
||||
|
||||
def segments_to_striped_markdown(segments: Iterable[markdown_segment], test_language: str = "python") -> Generator[str, None, None]:
|
||||
for segment in segments:
|
||||
if segment.code_block:
|
||||
if segment.language == test_language:
|
||||
yield "``` " + test_language
|
||||
yield segment.text
|
||||
yield "```"
|
||||
|
||||
elif segment.language:
|
||||
for line in segment.text.splitlines():
|
||||
yield '# | ' + line
|
||||
yield ''
|
||||
|
||||
else:
|
||||
for line in segment.text.strip(' \n').splitlines():
|
||||
yield '# ' + line
|
||||
yield ''
|
||||
|
||||
|
||||
def segments_to_test(segments: Iterable[markdown_segment], script_language: str = "python") -> Generator[str, None, None]:
|
||||
|
||||
ret_block_flag = False
|
||||
|
||||
yield 'def run_test():'
|
||||
|
||||
for segment in segments:
|
||||
if segment.code_block:
|
||||
if segment.language == script_language:
|
||||
lines = [line for line in segment.text.splitlines() if line.strip()]
|
||||
ret_block_flag = lines[-1] if not re.match(r'^[^(]*=', lines[-1]) and not lines[-1].startswith('import ') else None
|
||||
print('Last line: ', ret_block_flag, '-----------', lines[-1])
|
||||
|
||||
yield ''
|
||||
yield ' print("---------------------------------------------------------")'
|
||||
yield ''
|
||||
if ret_block_flag:
|
||||
yield from [' ' + str(line) for line in segment.text.splitlines()[:-1]]
|
||||
yield f' print("-- Result (({ret_block_flag})):")'
|
||||
yield f' print(({ret_block_flag}).__repr__().strip())'
|
||||
else:
|
||||
yield from [' ' + str(line) for line in segment.text.splitlines()]
|
||||
|
||||
elif ret_block_flag:
|
||||
yield ' ref_str = r"""'
|
||||
yield from [str(line) for line in segment.text.splitlines()]
|
||||
yield '"""'
|
||||
yield f' print("-- Reference (({ret_block_flag})):")'
|
||||
yield ' print(ref_str.strip())'
|
||||
yield f' assert ({ret_block_flag}).__repr__().strip() == ref_str.strip()'
|
||||
ret_block_flag = False
|
||||
|
||||
yield '\nif __name__ == "__main__":'
|
||||
yield ' run_test()'
|
||||
|
||||
if __name__ == "__main__":
|
||||
format = sys.argv[1]
|
||||
assert format in ['test', 'script']
|
||||
convert_to(sys.argv[1], sys.argv[2], sys.argv[3])
|
|
@ -1,53 +1,11 @@
|
|||
import re
|
||||
from typing import Generator
|
||||
|
||||
|
||||
def convert_markdown_file(md_filename: str, out_filename: str):
|
||||
with open(md_filename, "r") as f_in:
|
||||
with open(out_filename, "w") as f_out:
|
||||
f_out.write('def run_test():\n')
|
||||
for block in markdown_to_code([line for line in f_in]):
|
||||
f_out.write(block + '\n')
|
||||
|
||||
|
||||
def markdown_to_code(lines: list[str], language: str = "python") -> Generator[str, None, None]:
|
||||
regex = re.compile(
|
||||
r"(?P<start>^```\s*(?P<block_language>(\w|-)*)\n)(?P<code>.*?\n)(?P<end>```)",
|
||||
re.DOTALL | re.MULTILINE,
|
||||
)
|
||||
blocks = [
|
||||
(match.group("block_language"), match.group("code"))
|
||||
for match in regex.finditer("".join(lines))
|
||||
]
|
||||
|
||||
ret_block_flag = False
|
||||
|
||||
for block_language, block in blocks:
|
||||
if block_language == language:
|
||||
lines = [line for line in block.splitlines() if line.strip()]
|
||||
ret_block_flag = lines[-1] if '=' not in lines[-1] else None
|
||||
|
||||
yield ''
|
||||
yield ' print("---------------------------------------------------------")'
|
||||
yield ''
|
||||
if ret_block_flag:
|
||||
yield from [' ' + str(line) for line in block.splitlines()[:-1]]
|
||||
else:
|
||||
yield from [' ' + str(line) for line in block.splitlines()]
|
||||
yield f' print("-- Result (({ret_block_flag})):")'
|
||||
yield f' print(({ret_block_flag}).__repr__().strip())'
|
||||
|
||||
elif ret_block_flag:
|
||||
yield ' ref_str = r"""'
|
||||
yield from [str(line) for line in block.splitlines()]
|
||||
yield '"""'
|
||||
yield f' print("-- Reference (({ret_block_flag})):")'
|
||||
yield ' print(ref_str.strip())'
|
||||
yield f' assert ({ret_block_flag}).__repr__().strip() == ref_str.strip()'
|
||||
ret_block_flag = False
|
||||
|
||||
import md_to_code
|
||||
|
||||
def test_readme():
|
||||
convert_markdown_file('README.md', 'tests/autogenerated_readme.py')
|
||||
md_to_code.convert_to('test', 'README.md', 'tests/autogenerated_readme.py')
|
||||
import autogenerated_readme
|
||||
autogenerated_readme.run_test()
|
||||
|
||||
def test_soec_example():
|
||||
md_to_code.convert_to('test', 'docs/source/examples/soec_methane.md', 'tests/autogenerated_soec_example.py')
|
||||
import autogenerated_soec_example
|
||||
autogenerated_soec_example.run_test()
|
Loading…
Reference in New Issue