Skip to content

Markdown Toolkit



A python library for creating and manipulating markdown with an object oriented interface.

Tests Pylint Coverage Package version Supported Python versions

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.py
    from 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
    
    ![img/ron_swanson.jpg](img/ron_swanson.jpg)
    
    *   **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

    img/ron_swanson.jpg

    • 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.py
    from 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())
    
    examples/injection_source.md
    # Accounts
    
    This page shows the state of the active customers at Example Co.
    
    <!--- markdown-toolkit:customers --->
    <!--- markdown-toolkit:customers --->
    
    _This page is regenerated by a script._
    
    # 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 |
    | --- | --- | --- | --- |
    | ![https://randomuser.me/api/portraits/thumb/women/84.jpg](https://randomuser.me/api/portraits/thumb/women/84.jpg)<br>Ms Heidi Martin | blueelephant929 (heidi.martin@example.com) | 75 | 875<br>Mill Road<br>York<br>United Kingdom<br>**AM4C 6GZ** |
    | ![https://randomuser.me/api/portraits/thumb/men/77.jpg](https://randomuser.me/api/portraits/thumb/men/77.jpg)<br>Mr Jeff Diaz | brownlion290 (jeff.diaz@example.com) | 74 | 2907<br>Queens Road<br>Bristol<br>United Kingdom<br>**EB1S 4HU** |
    | ![https://randomuser.me/api/portraits/thumb/women/34.jpg](https://randomuser.me/api/portraits/thumb/women/34.jpg)<br>Ms Leah Long | bigladybug864 (leah.long@example.com) | 49 | 5812<br>Stanley Road<br>Swansea<br>United Kingdom<br>**DO6Q 8UF** |
    | ![https://randomuser.me/api/portraits/thumb/women/83.jpg](https://randomuser.me/api/portraits/thumb/women/83.jpg)<br>Ms Grace Rose | goldenladybug266 (grace.rose@example.com) | 57 | 9037<br>The Green<br>Belfast<br>United Kingdom<br>**OC40 1GS** |
    | ![https://randomuser.me/api/portraits/thumb/men/35.jpg](https://randomuser.me/api/portraits/thumb/men/35.jpg)<br>Mr Christopher Edwards | happyzebra240 (christopher.edwards@example.com) | 46 | 3954<br>Park Road<br>Peterborough<br>United Kingdom<br>**K62 7LD** |
    | ![https://randomuser.me/api/portraits/thumb/men/57.jpg](https://randomuser.me/api/portraits/thumb/men/57.jpg)<br>Mr Darren Curtis | orangetiger489 (darren.curtis@example.com) | 47 | 3423<br>North Road<br>Wakefield<br>United Kingdom<br>**AY5F 3TF** |
    | ![https://randomuser.me/api/portraits/thumb/women/67.jpg](https://randomuser.me/api/portraits/thumb/women/67.jpg)<br>Mrs Lauren George | greenfish374 (lauren.george@example.com) | 47 | 7094<br>Main Road<br>Durham<br>United Kingdom<br>**D74 2WT** |
    | ![https://randomuser.me/api/portraits/thumb/men/46.jpg](https://randomuser.me/api/portraits/thumb/men/46.jpg)<br>Mr Jeffery Gutierrez | beautifulcat661 (jeffery.gutierrez@example.com) | 77 | 2771<br>Albert Road<br>Bangor<br>United Kingdom<br>**ZW0 6ZX** |
    | ![https://randomuser.me/api/portraits/thumb/women/9.jpg](https://randomuser.me/api/portraits/thumb/women/9.jpg)<br>Miss Alice Ruiz | crazyladybug440 (alice.ruiz@example.com) | 70 | 9347<br>Victoria Street<br>Truro<br>United Kingdom<br>**K5 1TB** |
    | ![https://randomuser.me/api/portraits/thumb/women/93.jpg](https://randomuser.me/api/portraits/thumb/women/93.jpg)<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
    https://randomuser.me/api/portraits/thumb/women/84.jpg
    Ms Heidi Martin
    blueelephant929 (heidi.martin@example.com) 75 875
    Mill Road
    York
    United Kingdom
    AM4C 6GZ
    https://randomuser.me/api/portraits/thumb/men/77.jpg
    Mr Jeff Diaz
    brownlion290 (jeff.diaz@example.com) 74 2907
    Queens Road
    Bristol
    United Kingdom
    EB1S 4HU
    https://randomuser.me/api/portraits/thumb/women/34.jpg
    Ms Leah Long
    bigladybug864 (leah.long@example.com) 49 5812
    Stanley Road
    Swansea
    United Kingdom
    DO6Q 8UF
    https://randomuser.me/api/portraits/thumb/women/83.jpg
    Ms Grace Rose
    goldenladybug266 (grace.rose@example.com) 57 9037
    The Green
    Belfast
    United Kingdom
    OC40 1GS
    https://randomuser.me/api/portraits/thumb/men/35.jpg
    Mr Christopher Edwards
    happyzebra240 (christopher.edwards@example.com) 46 3954
    Park Road
    Peterborough
    United Kingdom
    K62 7LD
    https://randomuser.me/api/portraits/thumb/men/57.jpg
    Mr Darren Curtis
    orangetiger489 (darren.curtis@example.com) 47 3423
    North Road
    Wakefield
    United Kingdom
    AY5F 3TF
    https://randomuser.me/api/portraits/thumb/women/67.jpg
    Mrs Lauren George
    greenfish374 (lauren.george@example.com) 47 7094
    Main Road
    Durham
    United Kingdom
    D74 2WT
    https://randomuser.me/api/portraits/thumb/men/46.jpg
    Mr Jeffery Gutierrez
    beautifulcat661 (jeffery.gutierrez@example.com) 77 2771
    Albert Road
    Bangor
    United Kingdom
    ZW0 6ZX
    https://randomuser.me/api/portraits/thumb/women/9.jpg
    Miss Alice Ruiz
    crazyladybug440 (alice.ruiz@example.com) 70 9347
    Victoria Street
    Truro
    United Kingdom
    K5 1TB
    https://randomuser.me/api/portraits/thumb/women/93.jpg
    Ms Erin Williams
    crazyostrich570 (erin.williams@example.com) 39 6697
    Windsor Road
    York
    United Kingdom
    LX5A 4PH

    This 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:

pip install markdown-toolkit

If you want to include it in a larger poetry project:

poetry add markdown-toolkit

Back to top