File: test_bytes.py

package info (click to toggle)
pydantic-core 2.37.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,784 kB
  • sloc: python: 34,800; javascript: 211; makefile: 126
file content (124 lines) | stat: -rw-r--r-- 4,420 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import re
from typing import Any

import pytest

from pydantic_core import SchemaValidator, ValidationError
from pydantic_core import core_schema as cs

from ..conftest import Err, PyAndJson


def test_strict_bytes_validator():
    v = SchemaValidator(cs.bytes_schema(strict=True))

    assert v.validate_python(b'foo') == b'foo'
    assert v.validate_json('"foo"') == b'foo'

    with pytest.raises(ValidationError, match='Input should be a valid bytes'):
        v.validate_python('foo')
    with pytest.raises(ValidationError, match='Input should be a valid bytes'):
        v.validate_python(bytearray(b'foo'))


def test_lax_bytes_validator():
    v = SchemaValidator(cs.bytes_schema())

    assert v.validate_python(b'foo') == b'foo'
    assert v.validate_python('foo') == b'foo'
    assert v.validate_python(bytearray(b'foo')) == b'foo'

    assert v.validate_json('"foo"') == b'foo'

    assert v.validate_python('🐈 Hello') == b'\xf0\x9f\x90\x88 Hello'
    # `.to_str()` Returns a `UnicodeEncodeError` if the input is not valid unicode (containing unpaired surrogates).
    # https://github.com/PyO3/pyo3/blob/6503128442b8f3e767c663a6a8d96376d7fb603d/src/types/string.rs#L477
    with pytest.raises(ValidationError) as exc_info:
        v.validate_python('🐈 Hello \ud800World')
    assert exc_info.value.errors(include_url=False) == [
        {
            'type': 'string_unicode',
            'loc': (),
            'msg': 'Input should be a valid string, unable to parse raw data as a unicode string',
            'input': '🐈 Hello \ud800World',
        }
    ]


@pytest.mark.parametrize(
    'opts,input,expected',
    [
        ({}, b'foo', b'foo'),
        ({'max_length': 5}, b'foo', b'foo'),
        ({'max_length': 5}, b'foobar', Err('Data should have at most 5 bytes')),
        ({'min_length': 2}, b'foo', b'foo'),
        ({'min_length': 2}, b'f', Err('Data should have at least 2 bytes')),
        ({'min_length': 1, 'max_length': 6, 'strict': True}, b'bytes?', b'bytes?'),
    ],
)
def test_constrained_bytes_python_bytes(opts: dict[str, Any], input, expected):
    v = SchemaValidator(cs.bytes_schema(**opts))
    if isinstance(expected, Err):
        with pytest.raises(ValidationError, match=re.escape(expected.message)):
            v.validate_python(input)
    else:
        assert v.validate_python(input) == expected


@pytest.mark.parametrize(
    'opts,input,expected',
    [
        ({}, 'foo', b'foo'),
        ({'max_length': 5}, 'foo', b'foo'),
        ({'max_length': 5}, 'foobar', Err('Data should have at most 5 bytes')),
        ({'min_length': 2}, 'foo', b'foo'),
        ({'min_length': 2}, 'f', Err('Data should have at least 2 bytes')),
        ({}, 1, Err('Input should be a valid bytes')),
        ({}, 1.0, Err('Input should be a valid bytes')),
        ({}, [], Err('Input should be a valid bytes')),
        ({}, {}, Err('Input should be a valid bytes')),
    ],
)
def test_constrained_bytes(py_and_json: PyAndJson, opts: dict[str, Any], input, expected):
    v = py_and_json({'type': 'bytes', **opts})
    if isinstance(expected, Err):
        with pytest.raises(ValidationError, match=re.escape(expected.message)):
            v.validate_test(input)
        assert v.isinstance_test(input) is False
    else:
        assert v.validate_test(input) == expected
        assert v.isinstance_test(input) is True


def test_union():
    v = SchemaValidator(cs.union_schema(choices=[cs.str_schema(strict=True), cs.bytes_schema(strict=True)]))
    assert v.validate_python('oh, a string') == 'oh, a string'
    assert v.validate_python(b'oh, bytes') == b'oh, bytes'


def test_length_ctx():
    v = SchemaValidator(cs.bytes_schema(min_length=2, max_length=3))
    with pytest.raises(ValidationError) as exc_info:
        v.validate_python(b'1')
    assert exc_info.value.errors(include_url=False) == [
        {
            'type': 'bytes_too_short',
            'loc': (),
            'msg': 'Data should have at least 2 bytes',
            'input': b'1',
            'ctx': {'min_length': 2},
        }
    ]

    with pytest.raises(ValidationError) as exc_info:
        v.validate_python(b'1234')

    assert exc_info.value.errors(include_url=False) == [
        {
            'type': 'bytes_too_long',
            'loc': (),
            'msg': 'Data should have at most 3 bytes',
            'input': b'1234',
            'ctx': {'max_length': 3},
        }
    ]