Skip to content

Get started

The includepy package provides a Markdown preprocessor that allows you to include the source code for a specific Python object (e.g., a function or class) when rendering Markdown content.

Note

This extension works with all of the standard code block features, such as line numbering, line highlighting, and code annotations. See Including a function for an example.

Installation

Install includepy with pip:

pip install includepy

Configuration

Add the following settings to your Zensical or MkDocs configuration:

[project.markdown_extensions.includepy]
markdown_extensions:
  - includepy

Example Python file

We use the following example.py file in the examples below:

example.py
"""
Example functions for inclusion in a code block.
"""


def something(arg1, arg2):
    return f"{arg1} and {arg2}"


def hello(name: str) -> None:
    print(f"Hello {name}!")


def factorial(n: int) -> int:
    value = n  # (1)
    while n > 1:
        n -= 1
        value *= n
    return value


class MyClass:
    def do_thing(self, value: str) -> str:
        return f"MyClass: {value}"

Including a function

If you write the following Markdown:

```py title="The factorial function", linenums="1", hl_lines="3-5"
-->includepy<-- example.py
-->pyobject<-- factorial
```

1. This is a code annotation.

You will get the following HTML:

The factorial function
def factorial(n: int) -> int:
    value = n  # (1)
    while n > 1:
        n -= 1
        value *= n
    return value
  1. This is a code annotation.

Including a class

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- MyClass
```

You will get the following HTML:

class MyClass:
    def do_thing(self, value: str) -> str:
        return f"MyClass: {value}"

Including a class method

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- MyClass.do_thing
```

You will get the following HTML:

def do_thing(self, value: str) -> str:
    return f"MyClass: {value}"

Adding content before/after

If you write the following Markdown:

```py
x = 1
-->includepy<-- example.py
-->pyobject<-- factorial
y = 2
```

You will get the following HTML:

x = 1
def factorial(n: int) -> int:
    value = n  # (1)
    while n > 1:
        n -= 1
        value *= n
    return value
y = 2

Including only a subset of lines

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- factorial
-->only_lines<-- 1,3-4,-2,5-
```

You will get the following HTML:

def factorial(n: int) -> int:
    while n > 1:
        n -= 1
def factorial(n: int) -> int:
    value = n  # (1)
        value *= n
    return value

The only_lines option accepts one or more line ranges, separated by commas, and each line range can take any of the following forms:

  • "n": Line number n;
  • "m-n": All lines from number m to number n (inclusive);
  • "m-": All lines from number m to the end (inclusive); and
  • "-n": All lines from the start to line number n (inclusive).

Note that line numbers start at 1.

Adding extra indentation

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- factorial
-->extra_indent<-- 4
```

You will get the following HTML:

    def factorial(n: int) -> int:
        value = n  # (1)
        while n > 1:
            n -= 1
            value *= n
        return value

Including extra lines

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- factorial
-->lines_before<-- 4
-->lines_after<-- 4
```

You will get the following HTML:

def hello(name: str) -> None:
    print(f"Hello {name}!")


def factorial(n: int) -> int:
    value = n  # (1)
    while n > 1:
        n -= 1
        value *= n
    return value


class MyClass:
    def do_thing(self, value: str) -> str:

Note

When including only a subset of lines, line numbering begins at the first included line.

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- factorial
-->lines_before<-- 4
-->only_lines<-- 1-2
```

You will get the following HTML:

def hello(name: str) -> None:
    print(f"Hello {name}!")

Note

Extra lines will be truncated if they would extend before the first line or after the final line of the source file.

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- something
-->lines_before<-- 40
```

You will get the following HTML:

"""
Example functions for inclusion in a code block.
"""


def something(arg1, arg2):
    return f"{arg1} and {arg2}"

If you write the following Markdown:

```py
-->includepy<-- example.py
-->pyobject<-- MyClass
-->lines_after<-- 40
```

You will get the following HTML:

class MyClass:
    def do_thing(self, value: str) -> str:
        return f"MyClass: {value}"

Removing docstrings

Consider the following examples/docstring.py file:

examples/docstring.py
"""
This module is used to test the `"strip_docstring"` option.
"""


def my_function():
    """
    We want to strip this docstring when including the code for this function.
    """
    return 1

If you write the following Markdown:

```py
-->includepy<-- examples/docstring.py
-->pyobject<-- my_function
-->strip_docstring<-- true
```

You will get the following HTML:

def my_function():
    return 1

If there is no docstring, the strip_docstring option has no effect.

Note

Docstrings are removed before the only_lines option takes effect.

If you write the following Markdown:

```py
-->includepy<-- examples/docstring.py
-->pyobject<-- my_function
-->strip_docstring<-- true
-->only_lines<-- 1-2
```

You will get the following HTML:

def my_function():
    return 1

Nested in a list

If you write the following Markdown:

- One thing

- Another thing:

    ```py
    -->includepy<-- example.py
    -->pyobject<-- factorial

    -->includepy<-- example.py
    -->pyobject<-- MyClass.do_thing
    ```

You will get the following HTML:

  • One thing

  • Another thing:

    def factorial(n: int) -> int:
        value = n  # (1)
        while n > 1:
            n -= 1
            value *= n
        return value
    
    def do_thing(self, value: str) -> str:
        return f"MyClass: {value}"
    

Escaping includepy blocks

If you write the following Markdown:

;-->includepy<-- example.py
;-->pyobject<-- factorial

You will get the following HTML:

-->includepy<-- example.py
-->pyobject<-- factorial

You can use any number of semi-colons. For example, to show how to escape a includepy block you can write the following Markdown:

;;-->includepy<-- example.py
;;-->pyobject<-- factorial

You will get the following HTML:

;-->includepy<-- example.py
;-->pyobject<-- factorial