Markdown Toolkit¶
A python library for creating and manipulating markdown with an object oriented interface.
This library is split into two aims:
- Generation of markdown with python to create documents or fragments of documents.
-
Injection of static text, file contents, or dynamically generated markdown into existing documents.
-
Generation¶
This example reaches out to a public API, grabs a response and generates a document using those dynamic responses using the MarkdownDocument class.
examples/document_quickstart.pyfrom datetime import datetime import requests from markdown_toolkit import MarkdownDocument, bold, image QUOTES_COUNT = 10 def calculate_age() -> int: year = 365 * 24 * 60 * 60 rons_birthday = datetime(year=1967, month=4, day=30) now = datetime.now() return int(divmod((now - rons_birthday).total_seconds(), year)[0]) quotes = requests.get( f"http://ron-swanson-quotes.herokuapp.com/v2/quotes/{QUOTES_COUNT}" ) doc = MarkdownDocument() with doc.heading("Ron Swanson"): with doc.heading("Biography"): doc.paragraph(image(uri="img/ron_swanson.jpg")) doc.list(f'{bold("Name")}: Ronald Ulysses "Ron" Swanson') doc.list(f'{bold("Age")}: {calculate_age()}') with doc.heading(f"Top {QUOTES_COUNT} Greatest Quotes"): doc.paragraph( "Ron is known for some insightful quotes, here's some of the best:" ) for quote in quotes.json(): doc.list(quote) print(doc.render())# Ron Swanson ## Biography  * **Name**: Ronald Ulysses "Ron" Swanson * **Age**: 55 ## Top 10 Greatest Quotes Ron is known for some insightful quotes, here's some of the best: * I love riddles! * I believe luck is a concept invented by the weak to explain their failures. * When I'm done eating a Mulligan's meal, for weeks afterwards, there are flecks of meat in my mustache. And I refuse to clean it because every now and then a piece of meat will fall into my mouth. * If it doesn’t have meat, it’s a snack. * Veganism is the sad result of a morally corrupt mind. Reconsider your life. * Turkey can never beat cow. * I don't want to paint with a broad brush here, but every single contractor in the world is a miserable, incompetent thief. * History began July 4th, 1776. Anything before that was a mistake. * I like saying ‘No,’ it lowers their enthusiasm. * When I eat, it is the food that is scared.Ron Swanson¶
Biography¶

- Name: Ronald Ulysses "Ron" Swanson
- Age: 55
Top 10 Greatest Quotes¶
Ron is known for some insightful quotes, here's some of the best:
- I believe luck is a concept invented by the weak to explain their failures.
- Once a year, every branch of this government meets in a room and announces what they intend to waste taxpayer money on.
- My first ex-wife’s name is Tammy. My second ex-wife’s name is Tammy. My Mom’s name is Tamara…she goes by Tammy.
- The less I know about other people's affairs, the happier I am. I'm not interested in caring about people. I once worked with a guy for three years and never learned his name. Best friend I ever had. We still never talk sometimes.
- I'll take that steak to go. Please and thank you.
- On nights like this when the cold winds blow, the air is awash in the swirling eddies of our dream, come with me and find safe haven in a warm bathtub full of my jazz.
- The whole point of this country is if you want to eat garbage, balloon up to 600 pounds and die of a heart attack at 43, you can! You are free to do so. To me, that’s beautiful.
- Keep your tears in your eyes where they belong.
- I leave no meat behind. It’s an honor thing.
- Please and thank you.
-
Injection¶
This example takes a source document and uses a script to inject dynamically generated table markdown from an external HTTP request using both the MarkdownDocument and MarkdownInjector classes.
examples/injection_quickstart.pyfrom typing import Generator import requests from markdown_toolkit import MarkdownDocument, MarkdownInjector, bold, image, italic def get_customers(count: int = 1) -> Generator[dict]: response = requests.get( f"https://randomuser.me/api/?seed=markdown-toolkit&results={count}&nat=gb" ) for customer in response.json()["results"]: yield customer def customer_name(customer: dict) -> str: title = customer["name"]["title"] first = customer["name"]["first"] last = customer["name"]["last"] profile_photo = customer["picture"]["thumbnail"] return f"{image(uri=profile_photo)}<br>{title} {first} {last}" def customer_address(customer: dict) -> str: components = [ str(customer["location"]["street"]["number"]), customer["location"]["street"]["name"], customer["location"]["city"], customer["location"]["country"], bold(customer["location"]["postcode"]), ] return "<br>".join(components) with open("docs/examples/injection_source.md", "r", encoding="UTF-8") as file: source_document = MarkdownInjector(file) doc = MarkdownDocument() with doc.heading("Customers", level=2): doc.paragraph(f"List of Customers from the {italic('Database')}") with doc.table(titles=["Name", "Login", "Age", "Address"]) as table: for customer in get_customers(count=10): table.add_row( name=customer_name(customer), login=f'{customer["login"]["username"]} ({customer["email"]})', age=customer["dob"]["age"], address=customer_address(customer), ) source_document.anchors.customers.value = doc.render() print(source_document.render())# Accounts This page shows the state of the active customers at Example Co. <!--- markdown-toolkit:customers ---> ## Customers List of Customers from the _Database_ | Name | Login | Age | Address | | --- | --- | --- | --- | | <br>Ms Heidi Martin | blueelephant929 (heidi.martin@example.com) | 75 | 875<br>Mill Road<br>York<br>United Kingdom<br>**AM4C 6GZ** | | <br>Mr Jeff Diaz | brownlion290 (jeff.diaz@example.com) | 74 | 2907<br>Queens Road<br>Bristol<br>United Kingdom<br>**EB1S 4HU** | | <br>Ms Leah Long | bigladybug864 (leah.long@example.com) | 49 | 5812<br>Stanley Road<br>Swansea<br>United Kingdom<br>**DO6Q 8UF** | | <br>Ms Grace Rose | goldenladybug266 (grace.rose@example.com) | 57 | 9037<br>The Green<br>Belfast<br>United Kingdom<br>**OC40 1GS** | | <br>Mr Christopher Edwards | happyzebra240 (christopher.edwards@example.com) | 46 | 3954<br>Park Road<br>Peterborough<br>United Kingdom<br>**K62 7LD** | | <br>Mr Darren Curtis | orangetiger489 (darren.curtis@example.com) | 47 | 3423<br>North Road<br>Wakefield<br>United Kingdom<br>**AY5F 3TF** | | <br>Mrs Lauren George | greenfish374 (lauren.george@example.com) | 47 | 7094<br>Main Road<br>Durham<br>United Kingdom<br>**D74 2WT** | | <br>Mr Jeffery Gutierrez | beautifulcat661 (jeffery.gutierrez@example.com) | 77 | 2771<br>Albert Road<br>Bangor<br>United Kingdom<br>**ZW0 6ZX** | | <br>Miss Alice Ruiz | crazyladybug440 (alice.ruiz@example.com) | 70 | 9347<br>Victoria Street<br>Truro<br>United Kingdom<br>**K5 1TB** | | <br>Ms Erin Williams | crazyostrich570 (erin.williams@example.com) | 39 | 6697<br>Windsor Road<br>York<br>United Kingdom<br>**LX5A 4PH** | <!--- markdown-toolkit:customers ---> _This page is regenerated by a script._Accounts¶
This page shows the state of the active customers at Example Co.
Customers¶
List of Customers from the Database
Name Login Age Address 
Ms Heidi Martinblueelephant929 (heidi.martin@example.com) 75 875
Mill Road
York
United Kingdom
AM4C 6GZ
Mr Jeff Diazbrownlion290 (jeff.diaz@example.com) 74 2907
Queens Road
Bristol
United Kingdom
EB1S 4HU
Ms Leah Longbigladybug864 (leah.long@example.com) 49 5812
Stanley Road
Swansea
United Kingdom
DO6Q 8UF
Ms Grace Rosegoldenladybug266 (grace.rose@example.com) 57 9037
The Green
Belfast
United Kingdom
OC40 1GS
Mr Christopher Edwardshappyzebra240 (christopher.edwards@example.com) 46 3954
Park Road
Peterborough
United Kingdom
K62 7LD
Mr Darren Curtisorangetiger489 (darren.curtis@example.com) 47 3423
North Road
Wakefield
United Kingdom
AY5F 3TF
Mrs Lauren Georgegreenfish374 (lauren.george@example.com) 47 7094
Main Road
Durham
United Kingdom
D74 2WT
Mr Jeffery Gutierrezbeautifulcat661 (jeffery.gutierrez@example.com) 77 2771
Albert Road
Bangor
United Kingdom
ZW0 6ZX
Miss Alice Ruizcrazyladybug440 (alice.ruiz@example.com) 70 9347
Victoria Street
Truro
United Kingdom
K5 1TB
Ms Erin Williamscrazyostrich570 (erin.williams@example.com) 39 6697
Windsor Road
York
United Kingdom
LX5A 4PHThis page is regenerated by a script.
Installation¶
Warning
This library hasn't reached API stability, when it does it'll be bumped to version 1.0.0. Until then, make sure you pin your library versions.
To install the library directly for use in scripts you can install it directly with pip:
If you want to include it in a larger poetry project: