diff --git a/README.rst b/README.rst index 03f826e..42d2af3 100644 --- a/README.rst +++ b/README.rst @@ -128,52 +128,66 @@ unresolved-metaschema fallback warnings. assert validator_for(schema32) is OAS32Validator -Strict vs Pragmatic Validators -============================== +Binary Data Semantics +===================== -OpenAPI 3.0 has two validator variants with different behaviors for binary format: +The handling of binary-like payloads differs between OpenAPI versions. -**OAS30Validator (default - pragmatic)** - - Accepts Python ``bytes`` for ``type: string`` with ``format: binary`` - - More lenient for Python use cases where binary data is common - - Use when validating Python objects directly +OpenAPI 3.0 +----------- + +OpenAPI 3.0 keeps historical ``format: binary`` / ``format: byte`` usage on +``type: string``. + +**OAS30Validator (default - compatibility behavior)** + - ``type: string`` accepts ``str`` + - ``type: string, format: binary`` accepts Python ``bytes`` and strings + - useful when validating Python-native runtime data **OAS30StrictValidator** - - Follows OAS spec strictly: only accepts ``str`` for ``type: string`` - - For ``format: binary``, only accepts base64-encoded strings - - Use when strict spec compliance is required + - ``type: string`` accepts ``str`` only + - ``type: string, format: binary`` uses strict format validation + - use when you want strict, spec-oriented behavior for 3.0 schemas + +OpenAPI 3.1+ +------------ + +OpenAPI 3.1+ follows JSON Schema semantics for string typing in this library. -Comparison Matrix ------------------ +- ``type: string`` accepts ``str`` only (not ``bytes``) +- ``format: binary`` and ``format: byte`` are not treated as built-in formats +- for base64-in-JSON, model with ``contentEncoding: base64`` (optionally + ``contentMediaType``) +- for raw binary payloads, model via media type (for example + ``application/octet-stream``) rather than schema string formats + +Quick Reference +--------------- .. list-table:: :header-rows: 1 - :widths: 35 20 22 23 - - * - Schema - - Value - - OAS30Validator (default) - - OAS30StrictValidator - * - ``type: string`` - - ``"test"`` (str) - - Pass - - Pass - * - ``type: string`` - - ``b"test"`` (bytes) - - **Fail** - - **Fail** - * - ``type: string, format: binary`` - - ``b"test"`` (bytes) + :widths: 28 24 24 24 + + * - Context + - ``"text"`` (str) + - ``b"text"`` (bytes) + - Notes + * - OAS 3.0 + ``OAS30Validator`` - Pass - - **Fail** - * - ``type: string, format: binary`` - - ``"dGVzdA=="`` (base64) + - Pass for ``format: binary`` + - Compatibility behavior for Python runtime payloads + * - OAS 3.0 + ``OAS30StrictValidator`` - Pass + - Fail + - Strict 3.0 validation mode + * - OAS 3.1 + ``OAS31Validator`` - Pass - * - ``type: string, format: binary`` - - ``"test"`` (plain str) + - Fail + - Use ``contentEncoding``/``contentMediaType`` and media types + * - OAS 3.2 + ``OAS32Validator`` - Pass - - **Fail** + - Fail + - Same semantics as OAS 3.1 For more details read about `Validation `__. diff --git a/docs/validation.rst b/docs/validation.rst index c93aa69..7eccd33 100644 --- a/docs/validation.rst +++ b/docs/validation.rst @@ -166,54 +166,68 @@ OpenAPI 3.0 schema comes with ``readOnly`` and ``writeOnly`` keywords. In order ... ValidationError: Tried to write read-only property with 23 -Strict vs Pragmatic Validators ------------------------------- +Binary Data Semantics +--------------------- -OpenAPI 3.0 has two validator variants with different behaviors for binary format: +The handling of binary-like payloads differs between OpenAPI versions. -**OAS30Validator (default - pragmatic)** +OpenAPI 3.0 +~~~~~~~~~~~ -- Accepts Python ``bytes`` for ``type: string`` with ``format: binary`` -- More lenient for Python use cases where binary data is common -- Use when validating Python objects directly +OpenAPI 3.0 keeps historical ``format: binary`` / ``format: byte`` usage on +``type: string``. + +**OAS30Validator (default - compatibility behavior)** + +- ``type: string`` accepts ``str`` +- ``type: string, format: binary`` accepts Python ``bytes`` and strings +- useful when validating Python-native runtime data **OAS30StrictValidator** -- Follows OAS spec strictly: only accepts ``str`` for ``type: string`` -- For ``format: binary``, only accepts base64-encoded strings -- Use when strict spec compliance is required +- ``type: string`` accepts ``str`` only +- ``type: string, format: binary`` uses strict format validation +- use when you want strict, spec-oriented behavior for 3.0 schemas + +OpenAPI 3.1+ +~~~~~~~~~~~~ + +OpenAPI 3.1+ follows JSON Schema semantics for string typing in this library. -Comparison Matrix -~~~~~~~~~~~~~~~~~ +- ``type: string`` accepts ``str`` only (not ``bytes``) +- ``format: binary`` and ``format: byte`` are not treated as built-in formats +- for base64-in-JSON, model with ``contentEncoding: base64`` (optionally + ``contentMediaType``) +- for raw binary payloads, model via media type (for example + ``application/octet-stream``) rather than schema string formats + +Quick Reference +~~~~~~~~~~~~~~~ .. list-table:: :header-rows: 1 - :widths: 35 20 22 23 - - * - Schema - - Value - - OAS30Validator (default) - - OAS30StrictValidator - * - ``type: string`` - - ``"test"`` (str) - - Pass - - Pass - * - ``type: string`` - - ``b"test"`` (bytes) - - **Fail** - - **Fail** - * - ``type: string, format: binary`` - - ``b"test"`` (bytes) + :widths: 28 24 24 24 + + * - Context + - ``"text"`` (str) + - ``b"text"`` (bytes) + - Notes + * - OAS 3.0 + ``OAS30Validator`` - Pass - - **Fail** - * - ``type: string, format: binary`` - - ``"dGVzdA=="`` (base64) + - Pass for ``format: binary`` + - Compatibility behavior for Python runtime payloads + * - OAS 3.0 + ``OAS30StrictValidator`` - Pass + - Fail + - Strict 3.0 validation mode + * - OAS 3.1 + ``OAS31Validator`` - Pass - * - ``type: string, format: binary`` - - ``"test"`` (plain str) + - Fail + - Use ``contentEncoding``/``contentMediaType`` and media types + * - OAS 3.2 + ``OAS32Validator`` - Pass - - **Fail** + - Fail + - Same semantics as OAS 3.1 Example usage: diff --git a/tests/integration/test_validators.py b/tests/integration/test_validators.py index 65cc864..08f83ba 100644 --- a/tests/integration/test_validators.py +++ b/tests/integration/test_validators.py @@ -851,6 +851,26 @@ def test_string_disallow_binary(self, validator_class, value): with pytest.raises(ValidationError): validator.validate(value) + @pytest.mark.parametrize("value", [b"test"]) + def test_string_binary_rejects_bytes( + self, validator_class, format_checker, value + ): + schema = {"type": "string", "format": "binary"} + validator = validator_class(schema, format_checker=format_checker) + + with pytest.raises(ValidationError): + validator.validate(value) + + @pytest.mark.parametrize("value", [True, 3, 3.12, None]) + def test_string_binary_invalid( + self, validator_class, format_checker, value + ): + schema = {"type": "string", "format": "binary"} + validator = validator_class(schema, format_checker=format_checker) + + with pytest.raises(ValidationError): + validator.validate(value) + @pytest.mark.parametrize( "schema_type", [