Package: markdown-code-runner
:rocket: Markdown Code Runnermarkdown-code-runneris a Python package that automatically executes code blocks within a Markdown file, including hidden code blocks, and updates the output in-place.
This package is particularly useful for maintaining Markdown files with embedded code snippets, ensuring that the output displayed is up-to-date and accurate.
It also enables the generation of content such as tables, plots, and other visualizations directly from the code.The package is hosted on GitHub:https://github.com/basnijholt/markdown-code-runner:star: Features:rocket: Automatically execute code blocks, including hidden code blocks, within a Markdown file:eyes: Allows hidden code blocks (i.e., code blocks that are not displayed in the Markdown file) to generate content like tables, plots, etc.:snake: :shell: Works with Python and Bash code blocks:white_check_mark: Keeps the output of the code blocks up-to-date:octocat: Easily integrates with GitHub Actions:tada: No external dependencies and works with Python 3.7+:globe_with_meridians: Executealllanguages by using the file code blocks and executing it with bash (seeRust :crab: example):question: Problem StatementWhen creating Markdown files with code examples, it's essential to keep the output of these code snippets accurate and up-to-date.
Manually updating the output can be time-consuming and error-prone, especially when working with large files or multiple collaborators.
In addition, there might be cases where hidden code blocks are needed to generate content such as tables, plots, and other visualizations without displaying the code itself in the Markdown file.markdown-code-runnersolves this problem by automatically executing the code blocks, including hidden ones, within a Markdown file and updating the output in-place.
This ensures that the displayed output is always in sync with the code, and content generated by hidden code blocks is seamlessly integrated.:books: Table of Contents:computer: Installation:rocket: Quick Start:snake: Python API:book: Examples:star: Example 1: Simple code block:star: Example 2: Multiple code blocks:bulb: Usage Ideas:gear: Idea 1: Continuous Integration with GitHub Actions:computer: Idea 2: Show command-line output:bar_chart: Idea 3: Generating Markdown Tables:art: Idea 4: Generating Visualizations:page_facing_up: Idea 5: Generating a table from CSV data:star: Idea 5: Displaying API data as a list:crab: Idea 6: Run a Rust program:page_with_curl: License:handshake: Contributing:computer: InstallationInstallmarkdown-code-runnervia pip:pipinstallmarkdown-code-runner:rocket: Quick StartTo get started withmarkdown-code-runner, follow these steps:Add code blocks to your Markdown file using either of the following methods:Method 1 (show your code):Use a triple backtick code block with the language specifierpython markdown-code-runner.Example:```pythonmarkdown-code-runnerprint('Hello, world!')```(Optionally, you can place some text between the code block and the output markers)
<!-- OUTPUT:START -->
This content will be replaced by the output of the code block above.
<!-- OUTPUT:END -->or for Bash:```bashmarkdown-code-runnerecho'Hello, world!'```(Optionally, you can place some text between the code block and the output markers)
<!-- OUTPUT:START -->
This content will be replaced by the output of the code block above.
<!-- OUTPUT:END -->Method 2(hide your code):Place the code between<!-- CODE:START -->and<!-- CODE:END -->markers. Add the output markers<!-- OUTPUT:START -->and<!-- OUTPUT:END -->where you want the output to be displayed.Example:This is an example code block:

<!-- CODE:START -->
<!-- print('Hello, world!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
This content will be replaced by the output of the code block above.
<!-- OUTPUT:END -->or for Bash:This is an example code block:

<!-- CODE:BASH:START -->
<!-- MY_VAR="Hello, World!" -->
<!-- echo $MY_VAR -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
This content will be replaced by the output of the code block above.
<!-- OUTPUT:END -->Runmarkdown-code-runneron your Markdown file:markdown-code-runner/path/to/your/markdown_file.mdThe output of the code block will be automatically executed and inserted between the output markers.:snake: Python APITo usemarkdown-code-runner, simply import theupdate_markdown_filefunction from the package and call it with the path to your Markdown file:frommarkdown_code_runnerimportupdate_markdown_fileupdate_markdown_file("path/to/your/markdown_file.md"):book: ExamplesHere are a few examples demonstrating the usage ofmarkdown-code-runner::star: Example 1: Simple code blockThis is an example of a simple hidden code block:

<!-- CODE:START -->
<!-- print('Hello, world!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
This content will be replaced by the output of the code block above.
<!-- OUTPUT:END -->After runningmarkdown-code-runner:This is an example of a simple code block:

<!-- CODE:START -->
<!-- print('Hello, world!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by`markdown-code-runner`. -->
Hello, world!

<!-- OUTPUT:END -->:star: Example 2: Multiple code blocksHere are two code blocks:

First code block:

<!-- CODE:START -->
<!-- print('Hello, world!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
This content will be replaced by the output of the first code block.
<!-- OUTPUT:END -->Second code block:

<!-- CODE:START -->
<!-- print('Hello again!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
This content will be replaced by the output of the second code block.
<!-- OUTPUT:END -->After runningmarkdown-code-runner:Here are two code blocks:

First code block:

<!-- CODE:START -->
<!-- print('Hello, world!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by`markdown-code-runner`. -->
Hello, world!

<!-- OUTPUT:END -->

Second code block:

<!-- CODE:START -->
<!-- print('Hello again!') -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by`markdown-code-runner`. -->
Hello again!

<!-- OUTPUT:END -->:bulb: Usage IdeasMarkdown Code Runner can be used for various purposes, such as creating Markdown tables, generating visualizations, and showcasing code examples with live outputs. Here are some usage ideas to get you started::gear: Idea 1: Continuous Integration with GitHub ActionsYou can usemarkdown-code-runnerto automatically update your Markdown files in a CI environment.
The following example demonstrates how to configure a GitHub Actions workflow that updates yourREADME.mdwhenever changes are pushed to themainbranch.Create a new workflow file in your repository at.github/workflows/markdown-code-runner.yml.Add the following content to the workflow file:name:Update README.mdon:push:branches:-mainpull_request:jobs:update_readme:runs-on:ubuntu-lateststeps:-name:Check out repositoryuses:actions/checkout@v3with:persist-credentials:falsefetch-depth:0-name:Set up Pythonuses:actions/setup-python@v3with:python-version:'3.x'-name:Install markdown-code-runnerrun:|python -m pip install --upgrade pippip install markdown-code-runner# Install dependencies you're using in your README.md-name:Install other Python dependenciesrun:|pip install pandas tabulate pytest matplotlib requests# Rust is only needed for an example in our README.md-name:Set up Rustuses:actions-rs/toolchain@v1with:toolchain:stableprofile:minimal-name:Run update-readme.pyrun:markdown-code-runner --verbose README.md-name:Commit updated README.mdid:commitrun:|git add README.mdgit config --local user.email "github-actions[bot]@users.noreply.github.com"git config --local user.name "github-actions[bot]"if git diff --quiet && git diff --staged --quiet; thenecho "No changes in README.md, skipping commit."echo "commit_status=skipped" >> $GITHUB_ENVelsegit commit -m "Update README.md"echo "commit_status=committed" >> $GITHUB_ENVfi-name:Push changesif:env.commit_status == 'committed'uses:ad-m/github-push-action@masterwith:github_token:${{ secrets.GITHUB_TOKEN }}branch:${{ github.head_ref }}Commit and push the workflow file to your repository. The workflow will now automatically run whenever you push changes to themainbranch, updating yourREADME.mdwith the latest outputs from your code blocks.For more information on configuring GitHub Actions, check out theofficial documentation.:computer: Idea 2: Show command-line outputUsemarkdown-code-runnerto display the output of a command-line program. For example, the following Markdown file shows the helper options of this package.Using a backtick bash code block:exportPATH=~/micromamba/bin:$PATHecho'```bash'markdown-code-runner--helpecho'```'Which is rendered as:usage:markdown-code-runner[-h][-oOUTPUT][-d][-v]input

AutomaticallyupdateMarkdownfileswithcodeblockoutput.

positionalarguments:inputPathtotheinputMarkdownfile.

options:-h,--helpshowthishelpmessageandexit-oOUTPUT,--outputOUTPUTPathtotheoutputMarkdownfile.(default:overwriteinputfile)-d,--verboseEnabledebuggingmode(default:False)-v,--versionshowprogram'sversionnumberandexit:bar_chart: Idea 3: Generating Markdown TablesUse thepandaslibrary to create a Markdown table from a DataFrame. The following example demonstrates how to create a table with random data:importpandasaspdimportnumpyasnp# Generate random datanp.random.seed(42)data=np.random.randint(1,101,size=(5,3))# Create a DataFrame and column namesdf=pd.DataFrame(data,columns=["Column A","Column B","Column C"])# Convert the DataFrame to a Markdown tableprint(df.to_markdown(index=False))Which is rendered as:Column AColumn BColumn C529315726121838775758810024322:art: Idea 4: Generating VisualizationsCreate a visualization using thematplotliblibrary and save it as an image. Then, reference the image in your Markdown file. The following example demonstrates how to create a bar chart.Using a triple-backtick code block:importmatplotlib.pyplotaspltimportioimportbase64fromurllib.parseimportquote# Example data for the plotx=[1,2,3,4,5]y=[2,4,6,8,10]# Create a simple line plotplt.plot(x,y)plt.xlabel("X-axis")plt.ylabel("Y-axis")plt.title("Sample Line Plot")# Save the plot to a BytesIO bufferbuf=io.BytesIO()plt.savefig(buf,format='png')plt.close()# Encode the buffer as a base64 stringdata=base64.b64encode(buf.getvalue()).decode('utf-8')# Create an inline HTML img tag with the base64 stringfromurllib.parseimportquoteimg_html=f'<img src="data:image/png;base64,{quote(data)}" alt="Sample Line Plot"/>'print(img_html):information_source:NOTE: This output is disabled here because GitHub Markdown doesn't support inline image HTML. This will work on other Markdown renderers.:page_facing_up: Idea 5: Generating a table from CSV dataSuppose you have a CSV file containing data that you want to display as a table in your Markdown file.
You can usepandasto read the CSV file, convert it to a DataFrame, and then output it as a Markdown table.Using a triple-backtick code block:importpandasaspdcsv_data="Name,Age,Score\nAlice,30,90\nBob,25,85\nCharlie,22,95"withopen("sample_data.csv","w")asf:f.write(csv_data)df=pd.read_csv("sample_data.csv")print(df.to_markdown(index=False))Which is rendered as:NameAgeScoreAlice3090Bob2585Charlie2295:star: Idea 5: Displaying API data as a listYou can usemarkdown-code-runnerto make API calls and display the data as a list in your Markdown file.
In this example, we'll use therequestslibrary to fetch data from an API and display the results as a list.Using a hidden code block:<!-- CODE:START -->
<!-- import requests -->
<!-- response = requests.get("https://jsonplaceholder.typicode.com/todos?_limit=5") -->
<!-- todos = response.json() -->
<!-- for todo in todos: -->
<!--     print(f"- {todo['title']} (User ID: {todo['userId']}, Completed: {todo['completed']})") -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- OUTPUT:END -->Which is rendered as:delectus aut autem (User ID: 1, Completed: False)quis ut nam facilis et officia qui (User ID: 1, Completed: False)fugiat veniam minus (User ID: 1, Completed: False)et porro tempora (User ID: 1, Completed: True)laboriosam mollitia et enim quasi adipisci quia provident illum (User ID: 1, Completed: False):crab: Idea 6: Run a Rust programWe can usemarkdown-code-runnerto write Rust code to a file and then a hidden bash code block to run the code and display the output.The code belowis actually executed, check out theREADME.mdin plain textto see how this works.fnmain(){println!("Hello, world!");}Which when executed produces:Hello, world!These are just a few examples of how you can use Markdown Code Runner to enhance your Markdown documents with dynamic content. The possibilities are endless!:page_with_curl: Licensemarkdown-code-runneris released under theMIT License. Please include the LICENSE file when using this package in your project, and cite the original source.:handshake: ContributingContributions are welcome! To contribute, please follow these steps:Fork the repository on GitHub:https://github.com/basnijholt/markdown-code-runnerCreate a new branch for your changes.Make your changes, ensuring that they adhere to the code style and guidelines.Submit a pull request with a description of your changes.Please report any issues or bugs on the GitHub issue tracker:https://github.com/basnijholt/markdown-code-runner/issuesThank you for your interest inmarkdown-code-runner!