---
title: "Python Docstring Extractor"
description: "The fumapy Python package provides built-in docgen capabilities for extracting API documentation from Python source code and docstrings, serving as the official Python extension for Fumadocs. It br..."
last_updated: "2026-10-12T07:53:59.831064+00:00"
canonical_url: "https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/content-sources/python-docstring-extractor"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/python/fumapy/mksource/document_module.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/document_module.py)
- [packages/python/fumapy/mksource/simplify_docstring.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py)
- [packages/python/fumapy/mksource/models.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/models.py)
- [packages/python/fumapy/mksource/__init__.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/__init__.py)
- [packages/python/fumapy/__init__.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/__init__.py)
- [packages/python/fumapy/mksource/utils.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/utils.py)
- [packages/content/src/index.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/content/src/index.ts)
- [packages/python/src/convert.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts)
- [packages/python/pyproject.toml](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/pyproject.toml)
- [packages/mdx/src/runtime/server.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/mdx/src/runtime/server.ts)
- [packages/core/src/mdx-plugins/remark-structure.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/core/src/mdx-plugins/remark-structure.ts)
- [packages/typescript/src/lib/base.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/typescript/src/lib/base.ts)
- [packages/python/src/components/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/components/index.tsx)
- [packages/python/src/generated.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/generated.ts)
- [packages/content/src/runtime.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/content/src/runtime.ts)
- [packages/python/package.json](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/package.json)
- [packages/mdx/src/loaders/mdx/remark-postprocess.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/mdx/src/loaders/mdx/remark-postprocess.ts)
- [packages/openapi/src/utils/document/load.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/openapi/src/utils/document/load.ts)
- [packages/asyncapi/src/server/index.tsx](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/asyncapi/src/server/index.tsx)
- [packages/content-collections/src/configuration.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/content-collections/src/configuration.ts)
- [packages/mdx/src/runtime/types.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/mdx/src/runtime/types.ts)
- [packages/sanity/src/index.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/sanity/src/index.ts)
- [packages/twoslash/src/index.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/twoslash/src/index.ts)
- [packages/openapi/src/utils/pages/to-static-data.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/openapi/src/utils/pages/to-static-data.ts)
- [packages/python/fumapy/mksource/json_encoder.py](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/json_encoder.py)
- [packages/cli/src/commands/file-tree.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/cli/src/commands/file-tree.ts)
- [packages/doc-gen/package.json](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/doc-gen/package.json)
- [packages/asyncapi/src/utils/pages/to-static-data.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/asyncapi/src/utils/pages/to-static-data.ts)
- [packages/api-docs/src/i18n.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/api-docs/src/i18n.ts)
- [packages/preview/src/lib/source/storage.ts](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/preview/src/lib/source/storage.ts)
</details>

## Overview

The `fumapy` Python package provides built-in docgen capabilities for extracting API documentation from Python source code and docstrings, serving as the official Python extension for Fumadocs. It bridges raw Python modules and documentation frontends by inspecting AST structures, simplifying docstring content, and serializing parsed metadata into JSON format for static site generation.

Sources: [packages/python/pyproject.toml:4-4](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/pyproject.toml#L4-L4), [packages/python/package.json:4-4](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/package.json#L4-L4)

## Command Line and Execution Workflow

### CLI Entrypoint and Argument Configuration

The package registers a command-line script named `fumapy-generate` through `pyproject.toml`, pointing directly to the `generate` function within the main package module. 

```toml
[project.scripts]
fumapy-generate = "fumapy:generate"
```
Sources: [packages/python/pyproject.toml:10-11](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/pyproject.toml#L10-L11)

The `generate` function builds an `argparse.ArgumentParser` configured with positional and optional parameters to control target selection and output paths.

| Argument / Flag | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `module` | `str` | (Required) | The target Python module name to generate documentation for. |
| `--dir`, `-d` | `str` | `"."` | The target directory where the resulting JSON documentation file is saved. |

Sources: [packages/python/fumapy/__init__.py:30-41](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/__init__.py#L30-L41)

### Execution Lifecycle and Serialization

Once command-line arguments are parsed, the execution workflow initializes `griffe` with the `TypingDocExtension` extension. It loads the target module using `griffe.load`, setting `docstring_parser="auto"` and `store_source=True` based on module-level constants `DOCSTRING_TYPE` and `STORE_SOURCE`.

```python
    extensions = griffe.load_extensions(TypingDocExtension)
    pkg = parse_module(
        griffe.load(
            args.module, docstring_parser="auto", store_source=STORE_SOURCE, extensions=extensions
        )
    )
    api_filename = f"{args.module}.json"

    with open(os.path.join(args.dir, api_filename), "w") as file:
        json.dump(pkg, file, cls=CustomEncoder, indent=2, full=True)
```
Sources: [packages/python/fumapy/__init__.py:10-12](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/__init__.py#L10-L12), [packages/python/fumapy/__init__.py:43-52](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/__init__.py#L43-L52)

> [!NOTE]
> The generated documentation file is written as `{module}.json` inside the directory specified by `--dir`. The serialization process leverages `CustomEncoder` and enables `full=True` during `json.dump` to capture complete AST and docstring metadata.

Sources: [packages/python/fumapy/__init__.py:49-52](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/__init__.py#L49-L52)

## Griffe Inspection and AST Traversal

### Module AST Parsing

The `parse_module` function accepts a `griffe.Object` and verifies that it is an instance of `griffe.Module`, raising a `ValueError` otherwise. It processes module docstrings via `simplify_docstring` and builds a structured `Module` dictionary containing name, path, filepath, description, remaining docstring, attributes, submodules, classes, and functions while filtering out any aliases (`if not value.is_alias`).

```python
def parse_module(m: griffe.Object) -> Module:
    if not isinstance(m, griffe.Module):
        raise ValueError("Module must be a module")

    out = simplify_docstring(m.docstring, m)
    res: Module = {
        "name": m.name,
        "path": m.path,
        "filepath": m.filepath,
        "description": out.description,
        "docstring": out.remainder,
        "attributes": out.attributes,
        "modules": {
            name: parse_module(value)
            for name, value in m.modules.items()
            if not value.is_alias
        },
        "classes": {
            name: parse_class(value)
            for name, value in m.classes.items()
            if not value.is_alias
        },
        "functions": {
            name: parse_function(value)
            for name, value in m.functions.items()
            if not value.is_alias
        },
    }
    if m.is_package:
        try:
            res["version"] = version(m.name)
        except AttributeError:
            res["version"] = "unknown"

    return res
```
Sources: [packages/python/fumapy/mksource/document_module.py:12-46](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/document_module.py#L12-L46)

> [!NOTE]
> When `m.is_package` evaluates to true, `parse_module` attempts to dynamically retrieve the package version via `importlib.metadata.version(m.name)`, falling back to `"unknown"` if an `AttributeError` occurs.

Sources: [packages/python/fumapy/mksource/document_module.py:40-44](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/document_module.py#L40-L44)

### Class and Function AST Extraction

The `parse_class` function processes a `griffe.Class` object to extract its name, path, description, parameters, attributes, docstring, source code, non-alias functions, and inherited members. It parses inherited members by inspecting `c.inherited_members.values()`, extracting their canonical paths and kinds, and grouping them by their parent paths.

```python
def parse_class(c: griffe.Class) -> Class:
    out = simplify_docstring(c.docstring, c)
    res: Class = {
        "name": c.name,
        "path": c.path,
        "description": out.description,
        "parameters": out.parameters,
        "attributes": out.attributes,
        "docstring": out.remainder,
        "functions": {
            name: parse_function(value)
            for name, value in c.functions.items()
            if not value.is_alias
        },
        "source": c.source,
        "inherited_members": {},
    }
    for member in c.inherited_members.values():
        parent_path = ".".join(member.canonical_path.split(".")[:-1])
        member_info = {"kind": member.kind, "path": member.canonical_path}
        if parent_path not in res["inherited_members"]:
            res["inherited_members"][parent_path] = []
        res["inherited_members"][parent_path].append(member_info)
    return res
```
Sources: [packages/python/fumapy/mksource/document_module.py:49-72](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/document_module.py#L49-L72)

The `parse_function` function inspects a `griffe.Function` object, generating its signature via `build_signature(f)` and extracting its name, path, description, parameters, return annotations, docstring remainder, and source code.

```python
def parse_function(f: griffe.Function) -> Function:
    out = simplify_docstring(f.docstring, f)
    res: Function = {
        "name": f.name,
        "path": f.path,
        "signature": build_signature(f),
        "description": out.description,
        "parameters": out.parameters,
        "returns": out.returns,
        "docstring": out.remainder,
        "source": f.source,
    }
    return res
```
Sources: [packages/python/fumapy/mksource/document_module.py:75-86](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/document_module.py#L75-L86)

### Utility Functions and Helpers

Utility helpers support AST inspection by filtering non-imported objects, stringifying expressions, and building accurate Python callable signatures.

| Function | Parameters | Return Type | Description |
| :--- | :--- | :--- | :--- |
| `build_signature` | `func: griffe.Function` | `str` | Constructs a full function signature string, handling positional-only (`/`), keyword-only (`*`), varargs (`*args`), kwargs (`**kwargs`), defaults, and return annotations. |
| `filter_non_imported` | `d: dict[str, griffe.Object]` | `dict` | Filters a dictionary of Griffe objects to retain only those where `not v.is_imported`. |
| `stringify_expr` | `expr: griffe.Expr \| str` | `str` | Converts a Griffe expression into its string path representation or returns the string as-is. |

Sources: [packages/python/fumapy/mksource/utils.py:4-49](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/utils.py#L4-L49)

## Docstring Simplification and Signature Normalization

### Simplified Docstring Structure and Processing

The docstring transformation pipeline converts raw Griffe docstrings and AST inspection objects into structured dictionaries and named tuples via `simplify_docstring`. The `SimplifiedDocstring` named tuple contains five core fields: `description`, `parameters`, `returns`, `attributes`, and `remainder`. 

```python
class SimplifiedDocstring(t.NamedTuple):
    description: str | None
    parameters: list[dict[str, str | None]]
    returns: dict[str, str | None]
    attributes: list[dict[str, str | None]]
    remainder: list[griffe.DocstringSection]

```
Sources: [packages/python/fumapy/mksource/simplify_docstring.py:6-12](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py#L6-L12)

When processing a module, class, or function, helper routines initialize fields directly from the parent AST signatures before parsing individual docstring sections. Parameter annotations, default values, and attribute visibility filters are established during this initial signature pass.

```python
def get_parameters_from_signature(parent: griffe.Class | griffe.Function):
    return [
        {
            "name": p.name,
            "annotation": p.annotation,
            "description": None,
            "value": p.default,
        }
        for p in parent.parameters
    ]

def get_returns_from_signature(parent: griffe.Function):
    return {
        "name": "",
        "annotation": (
            parent.returns
            if isinstance(parent.returns, (str, type(None)))
            else "".join(
                elem if isinstance(elem, str) else elem.canonical_path
                for elem in parent.returns.iterate(flat=True)
            )
        ),
        "description": None,
    }

def get_attributes_from_signature(parent: griffe.Module | griffe.Class):
    return [
        {
            "name": attr.name,
            "annotation": attr.annotation,
            "description": attr.docstring.parsed if attr.docstring else None,
            "value": attr.value,
        }
        for attr in parent.attributes.values()
        if (not attr.is_alias and not attr.is_private)
    ]
```
Sources: [packages/python/fumapy/mksource/simplify_docstring.py:17-52](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py#L17-L52)

> [!WARNING]
> When iterating over parent attributes in `get_attributes_from_signature`, both `attr.is_alias` and `attr.is_private` items are explicitly excluded from the resulting list to prevent duplicate or private documentation entries.

Sources: [packages/python/fumapy/mksource/simplify_docstring.py:50-52](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py#L50-L52)

### Section Parsing and AST Merging

As `simplify_docstring` iterates through `doc.parsed`, it handles specific section kinds (`text`, `parameters`, `returns`, and `attributes`) while appending unhandled sections to `remainder`. Text sections appearing at index 0 populate the main description. Parameter and attribute sections merge docstring descriptions with runtime signature data by matching names against dictionaries constructed from parsed docstring section values.

```python
for i, sec in enumerate(doc.parsed):
    if sec.kind == "text" and i == 0:
        description = sec.value
        continue

    # Sort the parameters with the real signature
    if sec.kind == "parameters":
        map = {i.name: i for i in sec.value}
        params_list = []
        for param in parent.parameters:
            if param.name in map:
                docstring = map[param.name]
                try:
                    docstring.description = griffe.parse_google(
                        griffe.Docstring(docstring.description)
                    )
                except AttributeError:
                    pass
                params_list.append(docstring)
            else:
                params_list.append(
                    {
                        "name": param.name,
                        "annotation": param.annotation,
                        "description": None,
                        "value": param.default,
                    }
                )

        parameters = params_list
        continue

    if sec.kind == "returns":
        returns: griffe.DocstringReturn = sec.value[0]
        returns.annotation = (
            returns.annotation.canonical_path
            if isinstance(returns.annotation, griffe.Expr)
            else returns.annotation
        )
        continue
```
Sources: [packages/python/fumapy/mksource/simplify_docstring.py:76-115](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py#L76-L115)

> [!TIP]
> Parameter and attribute descriptions extracted from docstrings are re-parsed using `griffe.parse_google(griffe.Docstring(...))` to normalize Google-style formatting within individual item docstrings.

Sources: [packages/python/fumapy/mksource/simplify_docstring.py:89-91](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py#L89-L91), [packages/python/fumapy/mksource/simplify_docstring.py:135-137](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/simplify_docstring.py#L135-L137)

TypedDict definitions in `models.py` mirror these structures for downstream serialization and documentation rendering, ensuring strict type safety for parameters, attributes, functions, classes, and modules.

| Type Definition | Fields | Description |
| :--- | :--- | :--- |
| `Parameter` | `name`, `annotation`, `description`, `value` | Represents a single function or method parameter. |
| `Attribute` | `name`, `annotation`, `description`, `value` | Represents a class or module attribute. |
| `DocstringSection` | `kind`, `value` | Represents an unparsed or remaining docstring section. |
| `Function` | `name`, `path`, `signature`, `description`, `parameters`, `returns`, `docstring`, `source` | Typed dictionary capturing function metadata. |

Sources: [packages/python/fumapy/mksource/models.py:30-60](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/models.py#L30-L60)

## Serialization Models and JSON Encoding

### TypedDict Schema Models

TypedDict schemas define the structure for serialized Python modules, classes, and functions, mapping documentation metadata into strict dictionary types. The `Module` schema aggregates nested modules, classes, functions, attributes, and docstrings alongside metadata fields. The `Class` and `Function` schemas capture signature information, source code strings, parameters, and return mappings.

```python
class Module(t.TypedDict):
    name: str
    path: str
    filepath: str
    description: str | None
    docstring: Docstring
    attributes: list[Attribute]
    modules: dict[str, Module]
    classes: dict[str, Class]
    functions: dict[str, Function]
    version: str | None


class Class(t.TypedDict):
    name: str
    path: str
    description: str | None
    parameters: list[Parameter]
    attributes: list[Attribute]
    docstring: Docstring
    functions: dict[str, Function]
    source: str


class Function(t.TypedDict):
    name: str
    path: str
    signature: str
    description: str | None
    parameters: list[Parameter]
    returns: dict[str, str | None]
    docstring: Docstring
    source: str

```
Sources: [packages/python/fumapy/mksource/models.py:6-39](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/models.py#L6-L39)

> [!NOTE]
> `Docstring` is defined as a list of `DocstringSection` typed dictionaries, where each section holds a specific `kind` string and a `value` containing either plain text or a list of parameters.

Sources: [packages/python/fumapy/mksource/models.py:41-46](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/models.py#L41-L46)

### Custom JSON Encoder

The `CustomEncoder` class extends `griffe.JSONEncoder` to serialize Python path objects and expressions during export. A mapping table (`_json_encoder_map`) directs `Path`, `PosixPath`, and `WindowsPath` instances to `str` conversion, and Python `set` objects to sorted lists.

```python
_json_encoder_map: dict[type, t.Callable[[t.Any], t.Any]] = {
    Path: str,
    PosixPath: str,
    WindowsPath: str,
    set: sorted,
}
```
Sources: [packages/python/fumapy/mksource/json_encoder.py:5-10](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/json_encoder.py#L5-L10)

Within `CustomEncoder.default`, objects matching `griffe.Expr` are converted directly to strings via `str(obj)`, while standard inspected nodes invoke `obj.as_dict(full=self.full)`. Unrecognized types fall back to `_json_encoder_map` lookups or `super().default`.

```python
class CustomEncoder(griffe.JSONEncoder):
    def default(self, obj: t.Any) -> t.Any:
        """Return a serializable representation of the given object.

        Parameters:
            obj: The object to serialize.

        Returns:
            A serializable representation.
        """

        try:
            if isinstance(obj, griffe.Expr):
                return str(obj)
            return obj.as_dict(full=self.full)
        except AttributeError:
            return _json_encoder_map.get(type(obj), super().default)(obj)
```
Sources: [packages/python/fumapy/mksource/json_encoder.py:13-29](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/json_encoder.py#L13-L29)

> [!CAUTION]
> If `obj.as_dict()` raises an `AttributeError`, the encoder catches the exception and attempts fallback serialization through `_json_encoder_map` before resorting to the parent encoder.

Sources: [packages/python/fumapy/mksource/json_encoder.py:24-29](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/fumapy/mksource/json_encoder.py#L24-L29)

## Frontend Type Mapping and Rendering

### MDX Element Conversion and Layout

The `convert` function processes structured module objects into an array of output files by evaluating descriptions, attributes, nested classes, functions, and submodules. When classes or submodules are present, it dynamically builds layout structures using `Tabs` and `Cards` components, mapping entity paths with custom URL builders.

| Function / Utility | Target Element | Purpose |
| :--- | :--- | :--- |
| `convert` | `Tabs`, `Tab`, `Cards`, `Card` | Assembles module documentation into tabbed layouts and card grids. |
| `convertClass` | Markdown file (`.mdx`) | Generates standalone class documentation files with attribute and function sections. |
| `convertFunction` | `PyFunction` | Wraps function definitions, signatures, source code blocks, parameters, and return types. |
| `convertParameter` | `PyParameter` | Renders parameter entries with type annotations and default values. |
| `convertAttribute` | `PyAttribute` | Renders module or class attributes with optional annotations and default values. |

Sources: [packages/python/src/convert.ts:20-94](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts#L20-L94), [packages/python/src/convert.ts:96-126](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts#L96-L126), [packages/python/src/convert.ts:128-157](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts#L128-L157), [packages/python/src/convert.ts:159-171](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts#L159-L171), [packages/python/src/convert.ts:173-183](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts#L173-L183)

> [!WARNING]
> Text encoding performed by `encodeText` explicitly escapes less-than characters and curly braces to prevent syntax collision with MDX expressions during string serialization.

Sources: [packages/python/src/convert.ts:249-251](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/convert.ts#L249-L251)

### React Documentation Components

The rendering layer defines specialized React components styled with Tailwind CSS and class-variance-authority variants. Badge variants distinguish component categories using color themes for functions, attributes, classes, and primary parameters.

```tsx
const cardVariants = cva('bg-fd-card rounded-lg text-sm my-6 p-3 border');
const badgeVariants = cva('text-xs font-medium border p-1 rounded-lg not-prose', {
  variants: {
    color: {
      func: 'bg-fdpy-func/10 text-fdpy-func border-fdpy-func/50',
      attribute: 'bg-fdpy-attribute/10 text-fdpy-attribute border-fdpy-attribute/50',
      class: 'bg-fdpy-class/10 text-fdpy-class border-fdpy-class/50',
      primary: 'bg-fd-primary/10 text-fd-primary border-fd-primary/10',
    },
  },
});
```
Sources: [packages/python/src/components/index.tsx:13-23](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/components/index.tsx#L13-L23)

The `PySourceCode` component encapsulates function source blocks within collapsible containers that expose toggle triggers with chevron rotation indicators.

```tsx
export function PySourceCode({ children }: { children: ReactNode }) {
  return (
    <Collapsible className="my-6">
      <CollapsibleTrigger
        className={cn(
          buttonVariants({
            color: 'secondary',
            size: 'sm',
            className: 'group',
          }),
        )}
      >
        Source Code
        <ChevronRight className="size-3.5 text-fd-muted-foreground group-data-[state=open]:rotate-90" />
      </CollapsibleTrigger>
      <CollapsibleContent className="prose-no-margin">{children}</CollapsibleContent>
    </Collapsible>
  );
}
```
Sources: [packages/python/src/components/index.tsx:103-121](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/components/index.tsx#L103-L121)

> [!TIP]
> The `InlineCode` helper leverages [syntax highlighting](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/core-architecture/syntax-highlighting) on python code strings, customising pre-formatted spans to render inline type signatures cleanly.

Sources: [packages/python/src/components/index.tsx:135-149](https://github.com/blade47/fumadocs/blob/a9f988897e7dc4ef3d62b2865d80da2f5607701e/packages/python/src/components/index.tsx#L135-L149)

## Related

- [Source Loader](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/core-architecture/source-loader)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/llms.txt) for all pages in this wiki.
