Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support named blocks #16

Closed
sadda opened this issue Feb 27, 2023 · 3 comments
Closed

Support named blocks #16

sadda opened this issue Feb 27, 2023 · 3 comments

Comments

@sadda
Copy link

sadda commented Feb 27, 2023

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

@pawamoy
Copy link
Owner

pawamoy commented Feb 27, 2023

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.

@sadda
Copy link
Author

sadda commented Mar 13, 2023

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)

@pawamoy
Copy link
Owner

pawamoy commented Mar 15, 2023

@pawamoy pawamoy closed this as completed Mar 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants