Skip to content

Repository files navigation

AsciiDocstring

Build Status PyPI Version PyPI Downloads Python Versions License Coverage Ruff MyPy Pyodide Compatible

A pure-Python semantic parser, extractor, and translator for Python docstrings written in AsciiDoc. Fully compatible with Python 3.14+ and WASM/Pyodide environments with zero native compiled extensions.

1. Key Features

  • Pure Python & WASM/Pyodide Ready: Zero C-extensions or native binary dependencies.

  • Comprehensive Style Guide: Full specification and authoring guide for writing Python docstrings in AsciiDoc (see DOCSTRINGS.adoc).

  • Sphinx Integration: Converts AsciiDoc docstrings into Sphinx-compatible reStructuredText (reST).

  • Doctest Extraction: Queries and extracts executable code blocks and interactive prompts (>>>).

  • Semantic Docstring Inspection: Query structured docstring metadata including parameters, returns, yields, raises, receives, warns, attributes, deprecations, and examples as strongly typed dataclasses.

  • Griffe Ingestion Bridge: Ingest and parse docstrings via Griffe (Google, NumPy, and Sphinx styles) into AsciiDoc markup and bridge Griffe’s AST into structured AsciiDocStringDocument models.

  • Safe Mode & Graceful Fallbacks: Emits non-blocking warnings (AsciiDocStringWarning) with visual error carets during Sphinx builds instead of crashing.

  • Detailed Diagnostics: Rich exception reporting with precise line, column, and caret context previews on syntax errors.

2. Introduction & Architecture

asciidocstring is built on top of the pure-Python AsciiDoctrine parser. It is designed to cleanly process Python docstrings written in AsciiDoc, resolve indentation, and parse them into a lossless Abstract Semantic Graph (ASG).

  ┌────────────────────────┐         ┌────────────────────────┐
  │ Raw AsciiDoc Docstring │         │ Griffe Docstrings / AST│
  └───────────┬────────────┘         └───────────┬────────────┘
              │                                  │
              ▼                                  ▼
  ┌────────────────────────┐         ┌────────────────────────┐
  │ asciidocstring.parse() │◄────────┤ from_griffe() / Bridge │
  └───────────┬────────────┘         └────────────────────────┘
              │
              ▼
  ┌────────────────────────┐
  │ Abstract Semantic Graph│
  └───────────┬────────────┘
              │
      ┌───────┼──────────────────────────┬────────────────────────┐
      ▼                                  ▼                        ▼
┌───────────┐                      ┌───────────┐            ┌───────────┐
│ to_rest() │                      │extract_   │            │ Semantic  │
│           │                      │  tests()  │            │Properties │
└─────┬─────┘                      └─────┬─────┘            └─────┬─────┘
      │                                  │                        │
      ▼                                  ▼                        ▼
┌───────────┐                      ┌───────────┐            ┌───────────┐
│Sphinx reST│                      │Executable │            │Structured │
│           │                      │ Doctests  │            │  Models   │
└───────────┘                      └───────────┘            └───────────┘

This parsed semantic representation can be used by downstream libraries to:

  1. Render high-fidelity, Sphinx-compatible reStructuredText (reST) using Sphinx-AsciiDoctrine.

  2. Query and extract executable interactive doctest code blocks using AsciiDoctest.

  3. Inspect and query structured docstring metadata (parameters, returns, yields, raises, warns, attributes, deprecations) via strongly typed semantic properties.

  4. Ingest and bridge docstring sections from Griffe (supporting Google, NumPy, and Sphinx docstring conventions).

3. Installation

Initialize your project and install the library from PyPI:

pip install asciidocstring

To install with Griffe ingestion bridge support:

pip install "asciidocstring[griffe]"

To install optional developer dependencies (testing and linting tools):

pip install "asciidocstring[test,lint]"

4. Usage

4.1. Quick Start

import asciidocstring

docstring = """
    = Parse Coordinates

    This function processes dynamic coordinate objects.

    [source,python,test]
    ----
    assert parse_coords(10, 20) == (10, 20)
    ----

    x (int):: The horizontal component
    y (int):: The vertical component
    """

# Parse the raw docstring (automatically cleans leading docstring indentation)
doc = asciidocstring.parse(docstring)

# Translate the docstring into reStructuredText (reST) for Sphinx
rest_text = doc.to_rest()
print(rest_text)

# Extract code blocks tagged for doctesting
test_blocks = doc.extract_tests(language="python")
for block in test_blocks:
    print(f"Test Code ({block.language}):")
    print(block.content)

4.2. Semantic Docstring Inspection

AsciiDocStringDocument exposes structured, typed properties for programmatic inspection of docstrings:

import asciidocstring

docstring = """
    Calculate the Euclidean distance between two points.

    [parameters]
    `x1` (float):: The x-coordinate of the first point.
    `y1` (float):: The y-coordinate of the first point.
    `x2` (float, optional):: The x-coordinate of the second point. Defaults to `0.0`.
    `y2` (float, optional):: The y-coordinate of the second point. Defaults to `0.0`.

    [returns]
    `float`:: The Euclidean distance between the points.

    [raises]
    `TypeError`:: If any coordinate is non-numeric.
    """

doc = asciidocstring.parse(docstring)

# Access summary and full description
print(doc.summary)
# "Calculate the Euclidean distance between two points."

# Inspect parameters
for param in doc.parameters:
    print(f"{param.name} ({param.type_name}): optional={param.optional}, default={param.default}")
    print(f"  {param.description}")

# Inspect return types and exceptions
for ret in doc.returns:
    print(f"Returns {ret.type_name}: {ret.description}")

for exc in doc.raises:
    print(f"Raises {exc.type_name}: {exc.description}")

4.3. Griffe Ingestion & Conversion

Ingest and convert docstrings written in Google, NumPy, or Sphinx conventions into AsciiDoc markup and AsciiDocStringDocument models:

import asciidocstring

google_docstring = """
    Fetch data from a remote endpoint.

    Args:
        url (str): The destination URL.
        timeout (int, optional): Timeout in seconds. Defaults to 30.

    Returns:
        dict: The JSON response payload.

    Raises:
        ConnectionError: If connection fails.
"""

# Parse Google/NumPy/Sphinx docstrings using the Griffe bridge
doc = asciidocstring.from_griffe(google_docstring, style="google")

print(doc.summary)
# "Fetch data from a remote endpoint."

for param in doc.parameters:
    print(f"{param.name} ({param.type_name}): {param.description} [default: {param.default}]")

# Convert Griffe parsed sections directly to AsciiDoc markup
from griffe import parse as parse_griffe, Docstring

sections = parse_griffe(Docstring(google_docstring), "google")
adoc_markup = asciidocstring.to_asciidoc(sections)
print(adoc_markup)

4.4. Translation Comparison (AsciiDoc to reST)

Here is a side-by-side view of how AsciiDoc syntax in a docstring is translated into Sphinx-compatible reStructuredText:

Input AsciiDoc Docstring
Calculate the distance between two points.

[parameters]
`x`:: (`int`) The horizontal coordinate.
`y`:: (`int`) The vertical coordinate.
`origin`:: (`bool`, optional) Measure from origin. Defaults to `True`.

[returns]
`float`:: The Euclidean distance.
Output reStructuredText (reST)
Calculate the distance between two points.

``x``
   (``int``) The horizontal coordinate.

``y``
   (``int``) The vertical coordinate.

``origin``
   (``bool``, optional) Measure from origin. Defaults to ``True``.

``float``
   The Euclidean distance.

4.5. Catching Syntax and Parsing Errors

The library includes robust, structured syntax error handling. When parsing syntactically invalid AsciiDoc, an AsciiDocStringParseError is raised, detailing the exact location and a visual caret context.

import asciidocstring

invalid_docstring = """
    = Sample Header

    :: invalid-syntax
    """

try:
    asciidocstring.parse(invalid_docstring)
except asciidocstring.AsciiDocStringParseError as e:
    print(f"Error Message: {e}")
    print(f"Error Location: Line {e.line}, Column {e.column}")
    print("Caret Preview:")
    print(e.context)

Expected output:

Error Message: AsciiDoc Parse Error: Syntax error at line 3, column 1.
:: invalid-syntax
^
Error Location: Line 3, Column 1
Caret Preview:
:: invalid-syntax
^

4.6. Safe Mode Parsing & Warnings

By default, syntax violations raise an exception and halt Sphinx builds. To allow documentation to compile successfully even if a docstring contains syntax errors, you can enable safe_mode:

import asciidocstring

invalid_docstring = """
    = Sample Header

    :: invalid-syntax
    """

# Parse in safe mode (emits a non-blocking AsciiDocStringWarning)
doc = asciidocstring.parse(invalid_docstring, safe_mode=True)

# Generates a standard warning admonition containing the error and careted source
print(doc.to_rest())

Output:

.. warning::
   Failed to parse AsciiDoc docstring: AsciiDoc Parse Error: Syntax error at line 3, column 1.

   .. code-block:: asciidoc

      = Sample Header

      :: invalid-syntax
      ^

5. Docstring Authoring Guide

For a complete specification and guide on writing Python docstrings in AsciiDoc—including parameter annotations (LHS vs RHS), default value conventions, return types, yields/receives, exceptions, warnings, class attributes, deprecations, executable doctests, and best practices—consult our AsciiDoc Docstrings Guide (DOCSTRINGS.adoc).

6. API Reference

6.1. Functions

  • parse(docstring: str, safe_mode: bool = False) → AsciiDocStringDocument
    Convenience function to parse a raw Python docstring.

  • from_griffe(docstring: Union[Any, str], style: Literal["google", "numpy", "sphinx", "auto"] = "auto") → AsciiDocStringDocument
    Parse a docstring using Griffe’s parser and return a parsed AsciiDocStringDocument.

  • from_sections(sections: List[Any]) → AsciiDocStringDocument
    Convert a list of Griffe DocstringSection instances into an AsciiDocStringDocument.

  • to_asciidoc(sections: List[Any]) → str
    Convert a list of Griffe DocstringSection instances into clean AsciiDoc markup.

6.2. Classes

  • AsciiDocStringDocument
    The main interface representing a parsed docstring document.

    • init(raw_source: str, safe_mode: bool = False): Cleans and parses the given docstring.

    • to_rest() → str: Renders the parsed document as standard Sphinx-compatible reStructuredText.

    • extract_tests(language: str = "python", requires_test_marker: bool = False) → list[TestBlock]: Extracts executable code blocks.

    • summary (str): One-line summary (the first paragraph of the docstring).

    • description (str): Full extended docstring description.

    • parameters (list[DocstringParam]): Documented parameters extracted from [parameters] description lists.

    • returns (list[DocstringReturn]): Documented return values extracted from [returns] description lists.

    • yields (list[DocstringYield]): Documented yield values extracted from [yields] description lists.

    • raises (list[DocstringRaise]): Documented exceptions extracted from [raises] description lists.

    • receives (list[DocstringReceive]): Documented generator receive specifications extracted from [receives] description lists.

    • warns (list[DocstringWarn]): Documented warnings extracted from [warns] description lists.

    • attributes (list[DocstringAttribute]): Documented class/module attributes extracted from [attributes] description lists.

    • examples (list[DocstringExample]): Extracted example and test code blocks.

    • deprecated (DocstringDeprecated | None): Deprecation notice extracted from [deprecated] admonitions/blocks.

    • semantics (SemanticExtractorVisitor): Cached visitor containing all parsed semantic entities.

  • DocstringParam
    Represents a documented function, method, or class parameter.

    • name (str): Parameter name.

    • type_name (str | None): Type annotation string.

    • description (str): Parameter description.

    • default (str | None): Default value string.

    • optional (bool): Whether parameter is optional.

    • raw_entry (Any | None): Optional raw AST node reference.

  • DocstringReturn
    Represents a return value specification.

    • type_name (str | None): Return type annotation string.

    • description (str): Return value description.

    • name (str | None): Optional return identifier.

  • DocstringYield
    Represents a yield value specification.

    • type_name (str | None): Yield type annotation string.

    • description (str): Yield value description.

    • name (str | None): Optional yield identifier.

  • DocstringRaise
    Represents a documented exception that may be raised.

    • type_name (str): Exception class or type name.

    • description (str): Exception condition description.

  • DocstringReceive
    Represents a generator receive specification.

    • type_name (str | None): Received type annotation string.

    • description (str): Received value description.

  • DocstringWarn
    Represents a warning that may be issued.

    • type_name (str | None): Warning category or class name.

    • description (str): Warning trigger description.

  • DocstringAttribute
    Represents a class or module attribute.

    • name (str): Attribute name.

    • type_name (str | None): Type annotation string.

    • description (str): Attribute description.

    • value (str | None): Initial or default value string.

  • DocstringDeprecated
    Represents a deprecation notice.

    • version (str | None): Deprecated version.

    • reason (str): Deprecation reason or migration note.

  • DocstringExample
    Represents an example or test code block.

    • content (str): Source code content.

    • language (str): Language identifier (e.g. python).

    • line_number (int): 1-based starting line number.

    • is_interactive (bool): True if containing interactive >>> prompts.

    • attributes (dict): Dictionary of block attributes.

  • TestBlock
    Represents an extracted code block designed for execution or testing.

    • content (str): The raw code contents of the block.

    • language (str): The code block language (e.g. python).

    • line_number (int): The 1-based starting line number of the block in the docstring.

    • is_interactive (bool): True if the block contains python-interactive prompts (`>>> `).

    • attributes (dict): A dictionary of raw block attributes parsed from the AsciiDoc metadata.

  • AsciiDocStringParseError
    Raised when parsing an AsciiDoc docstring fails. Inherits from ValueError.

    • line (int | None): The line number of the parsing error.

    • column (int | None): The column number of the parsing error.

    • context (str | None): A visual text block indicating the line of code and a caret highlighting the syntax error position.

  • AsciiDocStringWarning
    Warning raised when parsing fails under safe_mode=True. Inherits from UserWarning.

7. Developer Guide

Ensure you have your environment set up and dependencies installed:

# Set up a virtual environment
python3 -m venv venv
source venv/bin/activate

# Install the package in editable mode with development dependencies
pip install -e ".[test,lint]"

7.1. Running Tests

We maintain 100% test coverage standards. To run tests and generate a coverage report:

PYTHONPATH=src pytest --cov=src --cov-report=term-missing

7.2. Static Analysis

Run our linting and type-safety check pipeline:

# Run Ruff code format and quality checks
ruff check src/ tests/

# Run MyPy type-safety validation
mypy src/

8. License

This project is licensed under the Apache License, Version 2.0.

About

Semantic extractor and parser of Python docstrings that are written in AsciiDoc. Also extracts Python source listing blocks from within the docstring.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages