From 3308067e5fd01984db856a5faa22f55dca0a29cf Mon Sep 17 00:00:00 2001 From: Roberto Prevato Date: Sat, 7 Mar 2026 08:04:43 +0100 Subject: [PATCH] Fix #64: use examples array and enum values in auto-generated schema examples - get_example_from_schema now checks for the JSON Schema draft 6+ 'examples' array (plural) and uses its first element as a fallback after 'example' (singular) but before dispatching to the type handler. - Moved enum handling from StringExampleHandler up to ScalarExampleHandler so that integer, number, and boolean properties with an 'enum' field also render the first enum value instead of falling through to the type default (0, 10.12, True). - 'example' (singular) still takes precedence over 'examples' (plural) which takes precedence over enum which takes precedence over type/format defaults. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 4 ++++ openapidocs/mk/v3/examples.py | 14 ++++++++------ tests/test_oas31.py | 31 ++++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f155cb..e308403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix [#60](https://github.com/Neoteroi/essentials-openapi/issues/60): resolve `$ref` values in response headers pointing to `#/components/headers/...` to avoid `UndefinedError` when rendering response tables, reported by @copiousfreetime. +- Fix [#64](https://github.com/Neoteroi/essentials-openapi/issues/64): use `examples` + array (JSON Schema draft 6+) as a fallback for auto-generated response examples; + also use `enum` values as examples for all scalar types (integer, number, boolean), + reported by @jan-ldwg. ## [1.3.0] - 2025-11-19 diff --git a/openapidocs/mk/v3/examples.py b/openapidocs/mk/v3/examples.py index d3e0123..97463aa 100644 --- a/openapidocs/mk/v3/examples.py +++ b/openapidocs/mk/v3/examples.py @@ -35,6 +35,10 @@ class ScalarExampleHandler(SchemaExampleHandler): formats: Dict[str, Callable[[], Any]] def get_example(self, schema) -> str: + enum = schema.get("enum") + if isinstance(enum, list) and enum: + return enum[0] + format = schema.get("format") if format and format in self.formats: @@ -56,12 +60,6 @@ class StringExampleHandler(ScalarExampleHandler): "binary": lambda: "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ=", } - def get_example(self, schema) -> str: - enum = schema.get("enum") - if isinstance(enum, list): - return enum[0] - return super().get_example(schema) - class IntegerExampleHandler(ScalarExampleHandler): type_name = "integer" @@ -138,6 +136,10 @@ def get_example_from_schema(schema) -> Any: if "example" in schema: return schema["example"] + examples = schema.get("examples") + if isinstance(examples, list) and examples: + return examples[0] + # does it have a type? handlers_types: List[Type[SchemaExampleHandler]] = list( get_subclasses(SchemaExampleHandler) diff --git a/tests/test_oas31.py b/tests/test_oas31.py index 965353d..09268ca 100644 --- a/tests/test_oas31.py +++ b/tests/test_oas31.py @@ -163,9 +163,34 @@ def test_null_only_type(self): assert get_example_from_schema({"type": ["null"]}) is None -# --------------------------------------------------------------------------- -# OpenAPIV3DocumentationHandler — OAS 3.1 rendering -# --------------------------------------------------------------------------- +class TestGetExampleFromSchemaAnnotations: + """Tests for JSON Schema draft 6+ examples array and enum handling.""" + + @pytest.mark.parametrize( + "schema, expected", + [ + # examples array (JSON Schema draft 6+) - first value should be used + ({"type": "string", "examples": ["A-DSP", "MON 1"]}, "A-DSP"), + ({"type": "integer", "examples": [42, 99]}, 42), + ({"type": "number", "examples": [3.14, 2.71]}, 3.14), + ({"type": "boolean", "examples": [False, True]}, False), + # example (singular) takes precedence over examples (plural) + ( + {"type": "string", "example": "override", "examples": ["A-DSP"]}, + "override", + ), + # empty examples list falls through to type handler + ({"type": "string", "examples": []}, "string"), + # enum on non-string types + ({"type": "integer", "enum": [1, 2, 3]}, 1), + ({"type": "number", "enum": [1.5, 2.5]}, 1.5), + ({"type": "boolean", "enum": [False]}, False), + # enum on string (pre-existing behaviour still works) + ({"type": "string", "enum": ["active", "inactive"]}, "active"), + ], + ) + def test_examples_and_enum(self, schema, expected): + assert get_example_from_schema(schema) == expected class TestOas31DocumentationHandler: