Add your description here
Project description
feather-structured-output
feather-structured-output is a lightweight Python library for turning LLM text
responses into validated Python dictionaries.
It does not call an LLM, retry requests, or manage conversation history. It only handles schema definition, short JSON prompt generation, JSON extraction, field validation, normalization, and retry-friendly error messages.
Installation
This repository uses uv.
uv run pytest
Basic Usage
from feather_structured_output import IntField, Schema, StringField
schema = Schema(
instruction="Extract the following JSON.",
fields=[
StringField(
source_label="Company name",
output_name="name",
description="Use the formal company name.",
example="Acme Corp",
),
IntField(
source_label="Quantity",
output_name="quantity",
gt=0,
),
],
)
prompt = schema.dump_prompt()
prompt becomes a compact JSON example with comments:
Extract the following JSON.
{
"name": "Acme Corp", // Company name。String. Use the formal company name. Required.
"quantity": 1 // Quantity。Integer. Greater than 0. Required.
}
Pass that prompt to any LLM client yourself, then validate the response:
result = schema.extract('{"name": "Acme Corp", "quantity": 3}')
if result.ok:
data = result.data
else:
retry_prompt = result.error_message
Fields
Available field types:
StringFieldIntFieldFloatFieldBooleanFieldObjectFieldUnionField
Common field options:
source_label: label from the source document or UI; optionaloutput_name: JSON key; if omitted,source_labelis useddescription: extra instruction for the LLMexample: sample value in the generated promptallowed_values: fixed allowed values for the fieldpresence: missing value policyrepeatable,min_items,max_items: array support
At least one of output_name or source_label is required when a field is used
in a Schema.
Presence Policy
from feather_structured_output import PresencePolicy, StringField
StringField(
output_name="note",
presence=PresencePolicy.NULLABLE,
)
Policies:
REQUIRED: value is requiredOMITTABLE: missing value is omitted from normalized dataNULLABLE: missing value is normalized toNoneBLANKABLE: missing value is normalized to""
"" is treated as a missing value during validation.
Arrays and Objects
from feather_structured_output import IntField, ObjectField, StringField
items = ObjectField(
output_name="items",
repeatable=True,
min_items=1,
fields=[
StringField(output_name="name"),
IntField(output_name="quantity", gt=0),
],
)
Fixed Values and Unions
Use allowed_values for fixed values. Use UnionField when a value may match
more than one field shape.
from feather_structured_output import IntField, StringField, UnionField
dog_age = UnionField(
output_name="dog_age",
variants=[
StringField(allowed_values=["N/A"]),
StringField(allowed_values=["-"]),
IntField(gt=0),
],
)
JSON Extraction
Schema.extract() accepts raw JSON or a single fenced json code block. Text
outside one JSON code block is ignored.
result = schema.extract(
"""Here is the result:
```json
{"name": "Acme Corp", "quantity": 3}
```"""
)
Multiple JSON code blocks, non-JSON code blocks, invalid JSON, and non-object
JSON values return ExtractResult with validation errors.
Custom Validators
Use validators for cross-field rules.
from feather_structured_output import IntField, Schema, StringField, ValidationError
def validate_octopus_legs(data: dict[str, object]) -> list[ValidationError]:
if data.get("pet") == "octopus" and data.get("legs") != 8:
return [
ValidationError(
path="legs",
message={
"en": "legs must be 8 when pet is octopus.",
"ja": "pet が octopus の場合、legs は 8 である必要があります。",
},
actual=data.get("legs"),
)
]
return []
schema = Schema(
fields=[
StringField(output_name="pet"),
IntField(output_name="legs", ge=0),
],
validators=[validate_octopus_legs],
)
Validators run only after field validation succeeds. Exceptions raised inside a validator are not converted to LLM-facing validation errors.
Error Messages and Locale
English is the default. Japanese retry messages are available with
locale="ja".
schema = Schema(
locale="ja",
fields=[IntField(output_name="quantity", gt=0)],
)
result = schema.extract('{"quantity": 0}')
print(result.error_message)
Internal message templates are split by locale under
src/feather_structured_output/locales/.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file feather_structured_output-0.1.1.tar.gz.
File metadata
- Download URL: feather_structured_output-0.1.1.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bfc69b8452e6bfb89d6c6da5848575d06d4a490e37b0fb9a2793bc3f8b1bffb7
|
|
| MD5 |
cb9f260d9835579315c59d18a3127ad6
|
|
| BLAKE2b-256 |
f6acd6e840514744d5b9dae1280d160cb049adb94e9d70c32c4267ad40d3fb72
|
File details
Details for the file feather_structured_output-0.1.1-py3-none-any.whl.
File metadata
- Download URL: feather_structured_output-0.1.1-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0213f42adf650bc7c5283892a7afb9e24ca7148826571dba90df86c678ab1573
|
|
| MD5 |
0ea9f5078d5b41e14f383d755f7994c1
|
|
| BLAKE2b-256 |
233670816bfd4783196287cad85103ed011de2c58c06f865d523d42abc003efd
|