Skip to main content

Schema-centric bidirectional conversion between text and structured data

Project description

dtxt

Schema-centric bidirectional conversion between text and structured data.

dtxt is not related to dtx (an AI red-teaming tool).

Core features

  1. Schema inference (infer_schema): derive a schema from a collection of texts
  2. T2D (parse): convert text into a schema-conformant object
  3. D2T (render): convert an object into text
  4. Round-trip verification (check_roundtrip): check that parse(render(obj)) ≈ obj for a given schema and backend

Install

pip install dtxt              # core only
pip install dtxt[anthropic]   # + Anthropic backend
pip install dtxt[openai]      # + OpenAI backend
pip install dtxt[llamacpp]    # + local GGUF models via llama.cpp
pip install dtxt[all]         # everything

The core package depends only on pydantic and jsonschema. Backends are optional extras, imported lazily.

Usage

import dtxt
from dtxt import Schema
from dtxt.backends import MockBackend

schema = Schema({
    "type": "object",
    "properties": {
        "name": {"type": "string", "x-dtxt-description": "the person's full name"},
        "age": {"type": "integer"},
    },
    "required": ["name", "age"],
})

# Backends can be set globally per function...
dtxt.configure(parse=MockBackend(), render=MockBackend())

# ...or overridden per call via backend=.
obj = dtxt.parse("Alice is 30 years old.", schema, backend=MockBackend())
text = dtxt.render({"name": "Alice", "age": 30}, schema)

result = dtxt.check_roundtrip({"name": "Alice", "age": 30}, schema)
result.ok  # True if parse(render(obj)) == obj on every schema field

Swap MockBackend for a real one:

dtxt.configure(
    infer=dtxt.backends.Anthropic("claude-sonnet-4-6"),
    parse=dtxt.backends.LlamaCpp("model.gguf", n_ctx=8192),
    render=dtxt.backends.Anthropic("claude-sonnet-4-6"),
)

Anthropic uses forced tool use to get structured output; OpenAI uses response_format={"type": "json_schema", ...}; LlamaCpp constrains decoding at the grammar level via GBNF. None of them guarantee full schema conformance on their own:

  • Anthropic/OpenAI guarantee valid JSON syntax, not every schema keyword.
  • LlamaCpp strips constructs GBNF can't reliably express (format, pattern, deeply nested objects/arrays) from the grammar-facing schema; the original schema is still checked afterwards.

So all three go through dtxt's retry + validation loop the same way. parse_many runs concurrently via asyncio for Anthropic/OpenAI, bounded by max_concurrency (default 8) to avoid tripping rate limits; LlamaCpp processes it sequentially in-process so its prompt cache stays warm. A partial batch failure raises one ParseError naming how many texts failed and the first failing index, rather than aborting on the first error.

Style is controllable at both the schema and call level:

schema = Schema({
    "type": "object",
    "properties": {"name": {"type": "string"}},
    "required": ["name"],
    "x-dtxt-style": "formal, third person",  # schema-wide default
})
dtxt.render(obj, schema)                       # uses "formal, third person"
dtxt.render(obj, schema, style="casual, upbeat")  # overrides it for this call

Status

Early development (0.0.x). M1-M5 of the milestone plan are implemented: Schema, parse / parse_many (asyncio-parallel + bounded concurrency for API backends), render (with schema-level and per-call style control), infer_schema (sampling + merge, min_coverage), check_roundtrip, configure, a mock backend for testing, and the Anthropic / OpenAI / llama.cpp backends. Not yet done: publishing to PyPI as 0.1.0 -- see CLAUDE.md for the milestone plan.

Development

uv sync --dev
uv run pytest
uv run ruff check . && uv run ruff format --check .
uv run mypy src/

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dtxt-0.1.0.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dtxt-0.1.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file dtxt-0.1.0.tar.gz.

File metadata

  • Download URL: dtxt-0.1.0.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for dtxt-0.1.0.tar.gz
Algorithm Hash digest
SHA256 69feadf53c087e0ed5ba105f4f2208f24a3f546f08ec7398880738a6609285f3
MD5 950329fd5af36a9fe120b33f9c645f7e
BLAKE2b-256 596bb983796f6cba114e98a3672f063446df35d67d8c94de448240cf04eaf23c

See more details on using hashes here.

File details

Details for the file dtxt-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dtxt-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for dtxt-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0390048c9590759f97007800e3b2f91f0fb8a0224aaff2f2bda418757f52e3cf
MD5 bd3dcfaeeed28e3e5d3f3dc1731fd63f
BLAKE2b-256 fc942f5a3c8687663e8e64c59e774161b9cc290ee0d2a70d3616e8fd626dc3be

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page