Support named blocks
Closed this issue · 3 comments
Hello, thanks a lot for the nice package. I would like to ask whether it is possible to use/add named blocks similarly to Julia Documenter.jl. I mean that I declare a variable in one block
```python exec="true"
x = 1
```
and then use it in another block
```python exec="true"
print(x)
```
I believe that this could be done by merging the blocks with the same name. Probably not the most time-efficient way as some code would be evaluated multiple times but it should work :)
Thanks a lot,
Lukas
Hello Lukas, thanks for the suggestion!
I can see another approach here: currently Python code is executed in the same process, with exec
. We pass a new dictionary as globals
for each code block. And I think we could save and reuse these dictionaries, by giving them names or something, to allow reusing them in later code blocks.
Hello, thanks for the reply. Honestly speaking, I am not able to judge your answer because I do not understand it :) I wrote a simple workaround in the way which I suggested in my original file (all the code is copied and run multiple times). It is not the best solution but it should work as a temporary one if anyone needs the same feature. It takes a file such as
```python exec="true" source="above" result="console" name="name1"
x = 1
print(x) # markdown-exec: hide
```
```python exec="true" source="above" result="console" name="name1"
y = x + 1
print(y) # markdown-exec: hide
```
and converts it to
```python exec="true" source="above" result="console"
x = 1
print(x) # markdown-exec: hide
```
```python exec="true" source="above" result="console"
x = 1 # markdown-exec: hide
y = x + 1
print(y) # markdown-exec: hide
```
The original file should start with a dot because otherwise it will be run and resulted in an error (files starting with a dot are ignored).
Here is the code to convert the files.
import numpy as np
def convert_file(filename1: str, filename2: str) -> None:
"""Converts files allowing to use named blocks for markdown-exec.
The named blocks must be in the form of
```python some_attribute="" name="block_name" other_attribute=""
The script merges the blocks and hides the lines_old of the previous blocks.
This is highly inefficient as it runs the same code multiple times.
The name of the original file should start with `.` (it is ignored when building documentation).
Args:
filename1 (str): Name of the original file with named blocks.
filename2 (str): Name of the converted file suitable for markdown-exec.
Examples:
Input file:
```python exec="true" source="above" result="console" name="name1"
x = 1
print(x) # markdown-exec: hide
```
```python exec="true" source="above" result="console" name="name1"
y = x + 1
print(y) # markdown-exec: hide
```
Output file:
```python exec="true" source="above" result="console" name="name1"
x = 1
print(x) # markdown-exec: hide
```
```python exec="true" source="above" result="console" name="name1"
x = 1 # markdown-exec: hide
y = x + 1
print(y) # markdown-exec: hide
```
"""
# Load the original file
with open(filename1) as f:
lines_old = f.readlines()
in_block = False # Checks whether we are in a block started by ```
blocks = {} # Dictionary of the saved blocks. Keys are block names
lines_new = [] # Lines of the new file
for line in lines_old:
if not in_block and line.startswith('```'):
# Starting a new block (header)
in_block = True
line_split = line.split(' ')
ii = np.where([x.startswith('name') for x in line_split])[0]
# Checks whether it is a named block
if len(ii) == 1:
# Extract the name of the block and remove it from the header
block_name = line_split.pop(ii[0])
block_name = block_name[6:]
line = ' '.join(line_split)
if block_name.endswith('\n'):
line += '\n'
block_name = block_name[:-2]
else:
block_name = block_name[:-1]
# Add the content of the previous blocks with the same name to the new file
lines_new.append(line)
if block_name in blocks:
for block_line in blocks[block_name]:
lines_new.append(block_line[:-1] + ' # markdown-exec: hide\n')
else:
blocks[block_name] = []
else:
block_name = None
lines_new.append(line)
elif in_block and not line.startswith('```'):
# Inside a block
if block_name is not None and not line.startswith('print'):
blocks[block_name].append(line)
lines_new.append(line)
elif in_block and line.startswith('```'):
# Finishing a block (footer)
in_block = False
lines_new.append(line)
else:
# Outside of a block
lines_new.append(line)
# Save to the converted file
with open(filename2, 'w') as f:
f.writelines(lines_new)
Try out v1.4.0: https://pawamoy.github.io/markdown-exec/usage/#sessions