Skip to content

Commit a3b9788

Browse files
authored
🐛 Fix handling of bool literals (#783)
1 parent 6aab4db commit a3b9788

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

src/serializers/type_serializers/literal.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ impl BuildSerializer for LiteralSerializer {
4444
let mut repr_args: Vec<String> = Vec::new();
4545
for item in expected {
4646
repr_args.push(item.repr()?.extract()?);
47-
if let Ok(int) = extract_i64(item) {
47+
if let Ok(bool) = item.downcast::<PyBool>() {
48+
expected_py.append(bool)?;
49+
} else if let Ok(int) = extract_i64(item) {
4850
expected_int.insert(int);
4951
} else if let Ok(py_str) = item.downcast::<PyString>() {
5052
expected_str.insert(py_str.to_str()?.to_string());

tests/serializers/test_literal.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,13 @@ def test_other_literal():
6161
def test_empty_literal():
6262
with pytest.raises(SchemaError, match='`expected` should have length > 0'):
6363
SchemaSerializer(core_schema.literal_schema([]))
64+
65+
66+
def test_bool_literal():
67+
s = SchemaSerializer(core_schema.literal_schema([False]))
68+
assert 'expected_int:{},expected_str:{},expected_py:Some(Py(' in plain_repr(s)
69+
70+
assert s.to_python(False) is False
71+
assert s.to_python(False, mode='json') is False
72+
assert s.to_python(True) is True
73+
assert s.to_json(False) == b'false'

tests/serializers/test_union.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import dataclasses
22
import json
33
import re
4+
from typing import Union
45

56
import pytest
7+
from typing_extensions import Literal
68

79
from pydantic_core import PydanticSerializationUnexpectedValue, SchemaSerializer, core_schema
810

911

12+
class BaseModel:
13+
def __init__(self, **kwargs) -> None:
14+
for name, value in kwargs.items():
15+
setattr(self, name, value)
16+
17+
1018
@pytest.mark.parametrize('input_value,expected_value', [(True, True), (False, False), (1, 1), (123, 123), (-42, -42)])
1119
def test_union_bool_int(input_value, expected_value):
1220
s = SchemaSerializer(core_schema.union_schema([core_schema.bool_schema(), core_schema.int_schema()]))
@@ -360,3 +368,31 @@ def __init__(self, name: str, price: float):
360368
assert s.to_python(User(name='foo', surname='bar')) == {'name': 'foo', 'surname': 'bar'}
361369
assert s.to_python(DBUser(name='foo', surname='bar', password_hash='x')) == {'name': 'foo', 'surname': 'bar'}
362370
assert s.to_json(DBUser(name='foo', surname='bar', password_hash='x')) == b'{"name":"foo","surname":"bar"}'
371+
372+
373+
@pytest.mark.parametrize(('data', 'json_value'), [(False, 'false'), ('abc', '"abc"')])
374+
def test_union_literal_with_other_type(data, json_value):
375+
class Model(BaseModel):
376+
value: Union[Literal[False], str]
377+
value_types_reversed: Union[str, Literal[False]]
378+
379+
s = SchemaSerializer(
380+
core_schema.model_schema(
381+
Model,
382+
core_schema.model_fields_schema(
383+
{
384+
'value': core_schema.model_field(
385+
core_schema.union_schema([core_schema.literal_schema([False]), core_schema.str_schema()])
386+
),
387+
'value_types_reversed': core_schema.model_field(
388+
core_schema.union_schema([core_schema.str_schema(), core_schema.literal_schema([False])])
389+
),
390+
}
391+
),
392+
)
393+
)
394+
395+
m = Model(value=data, value_types_reversed=data)
396+
397+
assert s.to_python(m) == {'value': data, 'value_types_reversed': data}
398+
assert s.to_json(m) == f'{{"value":{json_value},"value_types_reversed":{json_value}}}'.encode()

0 commit comments

Comments
 (0)