Skip to content

feat: add JSON Schema export functionality - #532

Open
doubledare704 wants to merge 3 commits into
alecthomas:masterfrom
doubledare704:feature/json-schema-export
Open

feat: add JSON Schema export functionality#532
doubledare704 wants to merge 3 commits into
alecthomas:masterfrom
doubledare704:feature/json-schema-export

Conversation

@doubledare704

Copy link
Copy Markdown
Contributor

Add comprehensive JSON Schema export capability to voluptuous schemas, addressing issue #408. This enables integration with modern IDEs, API documentation tools, and other validation systems.

Features:

  • Convert voluptuous schemas to JSON Schema format
  • Support for all major validators (Range, Length, Email, URL, etc.)
  • Handle composite validators (All, Any, ExactSequence)
  • Proper Required/Optional marker conversion
  • Nested object and array schema support
  • Default value handling with JSON serialization safety

API:

  • Schema.to_json_schema() method on Schema instances
  • to_json_schema() standalone function
  • Full backward compatibility maintained

Testing:

  • Comprehensive test suite with 100% coverage
  • Real-world example scenarios
  • Edge case handling
  • JSON serialization validation

Documentation:

  • Updated README with usage examples
  • Complete example script demonstrating features
  • Inline documentation and docstrings

Closes #408

Add comprehensive JSON Schema export capability to voluptuous schemas,
addressing issue alecthomas#408. This enables integration with modern IDEs,
API documentation tools, and other validation systems.

Features:
- Convert voluptuous schemas to JSON Schema format
- Support for all major validators (Range, Length, Email, URL, etc.)
- Handle composite validators (All, Any, ExactSequence)
- Proper Required/Optional marker conversion
- Nested object and array schema support
- Default value handling with JSON serialization safety

API:
- Schema.to_json_schema() method on Schema instances
- to_json_schema() standalone function
- Full backward compatibility maintained

Testing:
- Comprehensive test suite with 100% coverage
- Real-world example scenarios
- Edge case handling
- JSON serialization validation

Documentation:
- Updated README with usage examples
- Complete example script demonstrating features
- Inline documentation and docstrings

Closes alecthomas#408
- Replace bare except clause with specific exception types
- Fix all 17 mypy type checking errors:
  * Add proper type annotations for Dict[str, Any]
  * Replace callable with typing.Callable
  * Fix incompatible type assignments
  * Resolve indexing operation type issues
  * Add type safety for validator method parameters
- Remove unused import (voluptuous.validators)
- Maintain full backward compatibility and functionality

All flake8 and mypy checks now pass with zero issues.
All 162 existing tests continue to pass.
@doubledare704
doubledare704 force-pushed the feature/json-schema-export branch from efd7df1 to d8092eb Compare August 31, 2025 08:48
@alecthomas

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8092eb81d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread voluptuous/json_schema.py
"""
json_schema: Dict[str, Any] = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove the unconditional object type from root schemas

When the root conversion does not itself contain a type—for example Schema('x'), Schema(In(['x', 'y'])), Schema(Any(str, int)), or Schema(All(str, Length(min=2)))—the later update() retains this initial "type": "object". The exported schema therefore rejects every value accepted by these root schemas because a value cannot simultaneously be an object and the declared scalar alternative or constant.

Useful? React with 👍 / 👎.

Comment thread voluptuous/json_schema.py
Comment on lines +229 to +233
# Multiple different schemas - use prefixItems for ordered validation
return {
"type": "array",
"prefixItems": items_schemas,
"items": False, # No additional items allowed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Export heterogeneous sequence schemas as item alternatives

For schemas such as Schema([str, int]), Voluptuous tries every listed validator for every element and permits arbitrary length and order, but this branch emits an ordered two-element tuple schema with no additional items. Consequently valid inputs such as [1, 'x'] or ['x', 'y', 'z'] are rejected by the exported schema; items: {"anyOf": ...} is needed here, while ordered behavior belongs to ExactSequence.

Useful? React with 👍 / 👎.

Comment thread voluptuous/json_schema.py
Comment on lines +200 to +203
# Regular key
prop_name = str(key)
json_schema["properties"][prop_name] = self._convert_schema_element(
value

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve validator-based mapping keys

When a mapping uses a key validator, such as the documented feature-flag pattern {str: bool}, converting the validator to the literal property name "<class 'str'>" while disabling additional properties rejects every normal key such as "feature_a". Voluptuous applies these keys dynamically, so the export must represent their key/value constraints with patternProperties, propertyNames, or an appropriate additionalProperties schema rather than stringify the validator.

Useful? React with 👍 / 👎.

Comment thread voluptuous/json_schema.py
Comment on lines +151 to +155
json_schema: Dict[str, Any] = {
"type": "object",
"properties": {},
"additionalProperties": False,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor the Schema extra-key policy

The object conversion always starts with additionalProperties: false and never reads Schema.extra. Thus Schema({'x': str}, extra=ALLOW_EXTRA) accepts {'x': 'a', 'y': 1} in Voluptuous but its exported schema rejects it; REMOVE_EXTRA inputs are similarly accepted before transformation. The generated additional-properties behavior should be derived from the applicable Schema instance.

Useful? React with 👍 / 👎.

Comment thread voluptuous/json_schema.py
Comment on lines +159 to +162
for key, value in mapping.items():
if key is Extra:
json_schema["additionalProperties"] = True
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain the value constraint attached to Extra

For an explicit schema such as {Extra: int}, Voluptuous allows arbitrary keys only when their values are integers, but this branch emits plain additionalProperties: true and discards the associated value schema. The exported schema therefore accepts invalid values such as {'x': 'not-an-int'}; additionalProperties should contain the converted value schema.

Useful? React with 👍 / 👎.

Comment thread voluptuous/json_schema.py
Comment on lines +301 to +305
if hasattr(length_validator, 'min') and length_validator.min is not None:
schema["minLength"] = length_validator.min

if hasattr(length_validator, 'max') and length_validator.max is not None:
schema["maxLength"] = length_validator.max

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit array length keywords for array validators

When Length is combined with an array schema, for example All([int], Length(min=2, max=3)), this converter emits minLength and maxLength. Those keywords apply only to strings and are ignored for arrays, so the exported schema accepts arrays of any size even though Voluptuous rejects them; the surrounding validated type must determine whether to emit minItems/maxItems (or minProperties/maxProperties) instead.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

export/generate json schema

2 participants