Skip to content

Commit 0625d81

Browse files
authored
Merge pull request #264 from python-openapi/fix/state-binary-data-semantics
State OAS binary data semantics
2 parents b0c6d18 + e713425 commit 0625d81

File tree

3 files changed

+116
-68
lines changed

3 files changed

+116
-68
lines changed

README.rst

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -128,52 +128,66 @@ unresolved-metaschema fallback warnings.
128128
assert validator_for(schema32) is OAS32Validator
129129
130130
131-
Strict vs Pragmatic Validators
132-
==============================
131+
Binary Data Semantics
132+
=====================
133133

134-
OpenAPI 3.0 has two validator variants with different behaviors for binary format:
134+
The handling of binary-like payloads differs between OpenAPI versions.
135135

136-
**OAS30Validator (default - pragmatic)**
137-
- Accepts Python ``bytes`` for ``type: string`` with ``format: binary``
138-
- More lenient for Python use cases where binary data is common
139-
- Use when validating Python objects directly
136+
OpenAPI 3.0
137+
-----------
138+
139+
OpenAPI 3.0 keeps historical ``format: binary`` / ``format: byte`` usage on
140+
``type: string``.
141+
142+
**OAS30Validator (default - compatibility behavior)**
143+
- ``type: string`` accepts ``str``
144+
- ``type: string, format: binary`` accepts Python ``bytes`` and strings
145+
- useful when validating Python-native runtime data
140146

141147
**OAS30StrictValidator**
142-
- Follows OAS spec strictly: only accepts ``str`` for ``type: string``
143-
- For ``format: binary``, only accepts base64-encoded strings
144-
- Use when strict spec compliance is required
148+
- ``type: string`` accepts ``str`` only
149+
- ``type: string, format: binary`` uses strict format validation
150+
- use when you want strict, spec-oriented behavior for 3.0 schemas
151+
152+
OpenAPI 3.1+
153+
------------
154+
155+
OpenAPI 3.1+ follows JSON Schema semantics for string typing in this library.
145156

146-
Comparison Matrix
147-
-----------------
157+
- ``type: string`` accepts ``str`` only (not ``bytes``)
158+
- ``format: binary`` and ``format: byte`` are not treated as built-in formats
159+
- for base64-in-JSON, model with ``contentEncoding: base64`` (optionally
160+
``contentMediaType``)
161+
- for raw binary payloads, model via media type (for example
162+
``application/octet-stream``) rather than schema string formats
163+
164+
Quick Reference
165+
---------------
148166

149167
.. list-table::
150168
:header-rows: 1
151-
:widths: 35 20 22 23
152-
153-
* - Schema
154-
- Value
155-
- OAS30Validator (default)
156-
- OAS30StrictValidator
157-
* - ``type: string``
158-
- ``"test"`` (str)
159-
- Pass
160-
- Pass
161-
* - ``type: string``
162-
- ``b"test"`` (bytes)
163-
- **Fail**
164-
- **Fail**
165-
* - ``type: string, format: binary``
166-
- ``b"test"`` (bytes)
169+
:widths: 28 24 24 24
170+
171+
* - Context
172+
- ``"text"`` (str)
173+
- ``b"text"`` (bytes)
174+
- Notes
175+
* - OAS 3.0 + ``OAS30Validator``
167176
- Pass
168-
- **Fail**
169-
* - ``type: string, format: binary``
170-
- ``"dGVzdA=="`` (base64)
177+
- Pass for ``format: binary``
178+
- Compatibility behavior for Python runtime payloads
179+
* - OAS 3.0 + ``OAS30StrictValidator``
171180
- Pass
181+
- Fail
182+
- Strict 3.0 validation mode
183+
* - OAS 3.1 + ``OAS31Validator``
172184
- Pass
173-
* - ``type: string, format: binary``
174-
- ``"test"`` (plain str)
185+
- Fail
186+
- Use ``contentEncoding``/``contentMediaType`` and media types
187+
* - OAS 3.2 + ``OAS32Validator``
175188
- Pass
176-
- **Fail**
189+
- Fail
190+
- Same semantics as OAS 3.1
177191

178192
For more details read about `Validation <https://openapi-schema-validator.readthedocs.io/en/latest/validation.html>`__.
179193

docs/validation.rst

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -166,54 +166,68 @@ OpenAPI 3.0 schema comes with ``readOnly`` and ``writeOnly`` keywords. In order
166166
...
167167
ValidationError: Tried to write read-only property with 23
168168
169-
Strict vs Pragmatic Validators
170-
------------------------------
169+
Binary Data Semantics
170+
---------------------
171171

172-
OpenAPI 3.0 has two validator variants with different behaviors for binary format:
172+
The handling of binary-like payloads differs between OpenAPI versions.
173173

174-
**OAS30Validator (default - pragmatic)**
174+
OpenAPI 3.0
175+
~~~~~~~~~~~
175176

176-
- Accepts Python ``bytes`` for ``type: string`` with ``format: binary``
177-
- More lenient for Python use cases where binary data is common
178-
- Use when validating Python objects directly
177+
OpenAPI 3.0 keeps historical ``format: binary`` / ``format: byte`` usage on
178+
``type: string``.
179+
180+
**OAS30Validator (default - compatibility behavior)**
181+
182+
- ``type: string`` accepts ``str``
183+
- ``type: string, format: binary`` accepts Python ``bytes`` and strings
184+
- useful when validating Python-native runtime data
179185

180186
**OAS30StrictValidator**
181187

182-
- Follows OAS spec strictly: only accepts ``str`` for ``type: string``
183-
- For ``format: binary``, only accepts base64-encoded strings
184-
- Use when strict spec compliance is required
188+
- ``type: string`` accepts ``str`` only
189+
- ``type: string, format: binary`` uses strict format validation
190+
- use when you want strict, spec-oriented behavior for 3.0 schemas
191+
192+
OpenAPI 3.1+
193+
~~~~~~~~~~~~
194+
195+
OpenAPI 3.1+ follows JSON Schema semantics for string typing in this library.
185196

186-
Comparison Matrix
187-
~~~~~~~~~~~~~~~~~
197+
- ``type: string`` accepts ``str`` only (not ``bytes``)
198+
- ``format: binary`` and ``format: byte`` are not treated as built-in formats
199+
- for base64-in-JSON, model with ``contentEncoding: base64`` (optionally
200+
``contentMediaType``)
201+
- for raw binary payloads, model via media type (for example
202+
``application/octet-stream``) rather than schema string formats
203+
204+
Quick Reference
205+
~~~~~~~~~~~~~~~
188206

189207
.. list-table::
190208
:header-rows: 1
191-
:widths: 35 20 22 23
192-
193-
* - Schema
194-
- Value
195-
- OAS30Validator (default)
196-
- OAS30StrictValidator
197-
* - ``type: string``
198-
- ``"test"`` (str)
199-
- Pass
200-
- Pass
201-
* - ``type: string``
202-
- ``b"test"`` (bytes)
203-
- **Fail**
204-
- **Fail**
205-
* - ``type: string, format: binary``
206-
- ``b"test"`` (bytes)
209+
:widths: 28 24 24 24
210+
211+
* - Context
212+
- ``"text"`` (str)
213+
- ``b"text"`` (bytes)
214+
- Notes
215+
* - OAS 3.0 + ``OAS30Validator``
207216
- Pass
208-
- **Fail**
209-
* - ``type: string, format: binary``
210-
- ``"dGVzdA=="`` (base64)
217+
- Pass for ``format: binary``
218+
- Compatibility behavior for Python runtime payloads
219+
* - OAS 3.0 + ``OAS30StrictValidator``
211220
- Pass
221+
- Fail
222+
- Strict 3.0 validation mode
223+
* - OAS 3.1 + ``OAS31Validator``
212224
- Pass
213-
* - ``type: string, format: binary``
214-
- ``"test"`` (plain str)
225+
- Fail
226+
- Use ``contentEncoding``/``contentMediaType`` and media types
227+
* - OAS 3.2 + ``OAS32Validator``
215228
- Pass
216-
- **Fail**
229+
- Fail
230+
- Same semantics as OAS 3.1
217231

218232
Example usage:
219233

tests/integration/test_validators.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,26 @@ def test_string_disallow_binary(self, validator_class, value):
851851
with pytest.raises(ValidationError):
852852
validator.validate(value)
853853

854+
@pytest.mark.parametrize("value", [b"test"])
855+
def test_string_binary_rejects_bytes(
856+
self, validator_class, format_checker, value
857+
):
858+
schema = {"type": "string", "format": "binary"}
859+
validator = validator_class(schema, format_checker=format_checker)
860+
861+
with pytest.raises(ValidationError):
862+
validator.validate(value)
863+
864+
@pytest.mark.parametrize("value", [True, 3, 3.12, None])
865+
def test_string_binary_invalid(
866+
self, validator_class, format_checker, value
867+
):
868+
schema = {"type": "string", "format": "binary"}
869+
validator = validator_class(schema, format_checker=format_checker)
870+
871+
with pytest.raises(ValidationError):
872+
validator.validate(value)
873+
854874
@pytest.mark.parametrize(
855875
"schema_type",
856876
[

0 commit comments

Comments
 (0)