tree: 7b7f6ba2791bed784f32bd1612c3851d2d5c7cd8
  1. python/
  2. BUILD.gn
  3. dap.json
  4. README.md
src/lib/debug/dap/README.md

Debug Adapter Protocol (DAP) Library

This library provides a complete and extensible implementation of the Debug Adapter Protocol (DAP) in Python.

Features

  • Protocol Models: Full set of Python types representing DAP requests, responses, and events.
  • Client Implementation: A DapClient that handles the message framing (Content-Length headers) and asynchronous request/response matching.
  • Extensible Architecture: Easy to add vendor-specific extensions without modifying the core library.

Client Usage Example

Here is a basic example of how to use the DapClient to connect to a debug adapter and send an initialize request:

import asyncio
from pydap.client import DapClient
from pydap.models import InitializeArguments


async def run():
    client = DapClient()

    # Connect to the debug adapter (e.g., via TCP)
    reader, writer = await asyncio.open_connection("127.0.0.1", 12345)

    # Send initialize request
    args = InitializeArguments(adapterID="test")

    # We create a task to send the request
    # In a full implementation, you would also have a task reading from 'reader'
    response = await client.initialize(writer, args)
    print(f"Response: {response}")


asyncio.run(run())

Naming Convention

To ensure idiomatic Python development while maintaining exact compliance with the DAP specification, this library defines models using standard Python snake_case (e.g., adapter_id) and uses Pydantic's aliasing feature to automatically serialize them to the required camelCase or acronym casing (e.g., adapterID) as defined in the official protocol.

Thanks to Pydantic's populate_by_name configuration, you can instantiate models using either snake_case or camelCase keyword arguments, though snake_case is preferred for idiomatic code.

Extensibility

One of the key design goals of this library is extensibility. The base protocol is often extended by specific debuggers to support unique features.

To extend the library:

  1. Define your custom argument types by subclassing DapBaseModel.
  2. Use the protected DapClient::_send_request method directly with your custom command string and model instance.

Example: Custom Profiling Extension

Suppose you are building a debug adapter that supports a custom profiling feature not covered by the standard protocol. You can extend DapClient to support this server feature by subclassing or using compositional mixin classes.

Step 1: Define Custom Arguments

from pydap.dap_types import DapBaseModel


class StartProfilingArguments(DapBaseModel):
    # Duration in milliseconds.
    duration: int

Step 2a: Direct Subclassing

import asyncio
from pydap.client import DapClient


class CustomDapClient(DapClient):

    async def start_profiling(
        self, writer: asyncio.StreamWriter, duration: int
    ):
        args = StartProfilingArguments(duration=duration)
        return await self._send_request(writer, "startProfiling", args)

Step 2b: Compositional Mixins (Recommended for Modular Extensions)

For complex clients with multiple independent extensions, mixin classes provide a cleaner architectural pattern:

import asyncio
from typing import Any, Protocol
from pydap.client import DapClient
from pydap.dap_types import DapBaseModel


# Define a protocol for type checking within the mixin
class DapClientProtocol(Protocol):

    async def _send_request(
        self,
        writer: asyncio.StreamWriter,
        command: str,
        arguments: DapBaseModel | None = None,
        timeout: float = 5.0,
    ) -> dict[str, Any]: ...


class ProfilingMixin:
    """Mixin class adding profiling support to a DapClient."""

    async def start_profiling(
        self: DapClientProtocol, writer: asyncio.StreamWriter, duration: int
    ) -> dict[str, Any]:
        args = StartProfilingArguments(duration=duration)
        return await self._send_request(writer, "startProfiling", args)


# Compose your final client from base DapClient and mixins
class ExtendedDapClient(DapClient, ProfilingMixin):
    pass