mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
594effa279
* working on core schema generation * adapting main.py * getting tests to run * fix tests * disable pyright, fix mypy * moving to class-based model generation * working on validators * change how models are created * start fixing test_main.py * fixing mypy * SelfType * recursive models working, more tests fixed * fix tests on <3.10 * get docs build to pass * starting to cleanup types.py * starting works on custom types * working on using annotated-types * using annoated types for constraints * lots of cleanup, fixing network tests * network tests passing 🎉 * working on types * working on types and cleanup * fixing UUID type, restructing again * more types and newer pydantic-core * working on Iterable * more test_types tests * support newer pydantic-core, fixing more test_types.py * working through more test_types.py * test_types.py at last passing locally 🎉 * fixing more tests in test_types.py * fix datetime_parse tests and linting * get tests running again, rename to test_datetime.py * renaming internal modules * working through mypy errors * fixing mypy * refactoring _generate_schema.py * test_main.py passing * uprev deps * fix conftest and linting? * importing Annotated * ltining * import Annotated from typing_extensions * fixing 3.7 compatibility * fixing tests on 3.9 * fix linting * fixing SecretField and 3.9 tests * customising get_type_hints * ignore warnings on 3.11 * spliting repr out of utils * removing unused bits of _repr, fix tests for 3.7 * more cleanup, removing many type aliases * clean up repr * support namedtuples and typeddicts * test is_union * removing errors, uprev pydantic-core * fix tests on 3.8 * fixing private attributes and model_post_init * renaming and cleanup * remove unnecessary PydanticMetadata inheritance * fixing forward refs and mypy tests * fix signatures, change how xfail works * revert mypy tests to 3.7 syntax * correct model title * try to fix tests * fixing ClassVar forward refs * uprev pydantic-core, new error format * add "force" argument to model_rebuild * Apply suggestions from code review Suggestions from @tiangolo and @hramezani 🙏 Co-authored-by: Hasan Ramezani <hasan.r67@gmail.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com> * more suggestions from @tiangolo * extra -> json_schema_extra on Field Co-authored-by: Hasan Ramezani <hasan.r67@gmail.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
203 lines
6.6 KiB
Python
203 lines
6.6 KiB
Python
from datetime import datetime
|
|
|
|
import pytest
|
|
from pydantic_core import PydanticCustomError
|
|
|
|
from pydantic import BaseModel, ValidationError
|
|
from pydantic.color import Color
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'raw_color, as_tuple',
|
|
[
|
|
# named colors
|
|
('aliceblue', (240, 248, 255)),
|
|
('Antiquewhite', (250, 235, 215)),
|
|
('#000000', (0, 0, 0)),
|
|
('#DAB', (221, 170, 187)),
|
|
('#dab', (221, 170, 187)),
|
|
('#000', (0, 0, 0)),
|
|
('0x797979', (121, 121, 121)),
|
|
('0x777', (119, 119, 119)),
|
|
('0x777777', (119, 119, 119)),
|
|
('0x777777cc', (119, 119, 119, 0.8)),
|
|
('777', (119, 119, 119)),
|
|
('777c', (119, 119, 119, 0.8)),
|
|
(' 777', (119, 119, 119)),
|
|
('777 ', (119, 119, 119)),
|
|
(' 777 ', (119, 119, 119)),
|
|
((0, 0, 128), (0, 0, 128)),
|
|
([0, 0, 128], (0, 0, 128)),
|
|
((0, 0, 205, 1.0), (0, 0, 205)),
|
|
((0, 0, 205, 0.5), (0, 0, 205, 0.5)),
|
|
('rgb(0, 0, 205)', (0, 0, 205)),
|
|
('rgb(0, 0, 205.2)', (0, 0, 205)),
|
|
('rgb(0, 0.2, 205)', (0, 0, 205)),
|
|
('rgba(0, 0, 128, 0.6)', (0, 0, 128, 0.6)),
|
|
('rgba(0, 0, 128, .6)', (0, 0, 128, 0.6)),
|
|
('rgba(0, 0, 128, 60%)', (0, 0, 128, 0.6)),
|
|
(' rgba(0, 0, 128,0.6) ', (0, 0, 128, 0.6)),
|
|
('rgba(00,0,128,0.6 )', (0, 0, 128, 0.6)),
|
|
('rgba(0, 0, 128, 0)', (0, 0, 128, 0)),
|
|
('rgba(0, 0, 128, 1)', (0, 0, 128)),
|
|
('hsl(270, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(180, 100%, 50%)', (0, 255, 255)),
|
|
('hsl(630, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(270deg, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(.75turn, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(-.25turn, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(-0.25turn, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(4.71238rad, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(10.9955rad, 60%, 70%)', (178, 133, 224)),
|
|
('hsl(270, 60%, 50%, .15)', (127, 51, 204, 0.15)),
|
|
('hsl(270.00deg, 60%, 50%, 15%)', (127, 51, 204, 0.15)),
|
|
],
|
|
)
|
|
def test_color_success(raw_color, as_tuple):
|
|
c = Color(raw_color)
|
|
assert c.as_rgb_tuple() == as_tuple
|
|
assert c.original() == raw_color
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'color',
|
|
[
|
|
# named colors
|
|
'nosuchname',
|
|
'chucknorris',
|
|
# hex
|
|
'#0000000',
|
|
'x000',
|
|
# rgb/rgba tuples
|
|
(256, 256, 256),
|
|
(128, 128, 128, 0.5, 128),
|
|
(0, 0, 'x'),
|
|
(0, 0, 0, 1.5),
|
|
(0, 0, 0, 'x'),
|
|
(0, 0, 1280),
|
|
(0, 0, 1205, 0.1),
|
|
(0, 0, 1128, 0.5),
|
|
(0, 0, 1128, -0.5),
|
|
(0, 0, 1128, 1.5),
|
|
# rgb/rgba strings
|
|
'rgb(0, 0, 1205)',
|
|
'rgb(0, 0, 1128)',
|
|
'rgba(0, 0, 11205, 0.1)',
|
|
'rgba(0, 0, 128, 11.5)',
|
|
'hsl(180, 101%, 50%)',
|
|
# neither a tuple, not a string
|
|
datetime(2017, 10, 5, 19, 47, 7),
|
|
object,
|
|
range(10),
|
|
],
|
|
)
|
|
def test_color_fail(color):
|
|
with pytest.raises(PydanticCustomError) as exc_info:
|
|
Color(color)
|
|
assert exc_info.value.type == 'color_error'
|
|
|
|
|
|
def test_model_validation():
|
|
class Model(BaseModel):
|
|
color: Color
|
|
|
|
assert Model(color='red').color.as_hex() == '#f00'
|
|
assert Model(color=Color('red')).color.as_hex() == '#f00'
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
Model(color='snot')
|
|
# insert_assert(exc_info.value.errors())
|
|
assert exc_info.value.errors() == [
|
|
{
|
|
'type': 'color_error',
|
|
'loc': ('color',),
|
|
'msg': 'value is not a valid color: string not recognised as a valid color',
|
|
'input': 'snot',
|
|
}
|
|
]
|
|
|
|
|
|
def test_as_rgb():
|
|
assert Color('bad').as_rgb() == 'rgb(187, 170, 221)'
|
|
assert Color((1, 2, 3, 0.123456)).as_rgb() == 'rgba(1, 2, 3, 0.12)'
|
|
assert Color((1, 2, 3, 0.1)).as_rgb() == 'rgba(1, 2, 3, 0.1)'
|
|
|
|
|
|
def test_as_rgb_tuple():
|
|
assert Color((1, 2, 3)).as_rgb_tuple(alpha=None) == (1, 2, 3)
|
|
assert Color((1, 2, 3, 1)).as_rgb_tuple(alpha=None) == (1, 2, 3)
|
|
assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=None) == (1, 2, 3, 0.3)
|
|
assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=None) == (1, 2, 3, 0.3)
|
|
|
|
assert Color((1, 2, 3)).as_rgb_tuple(alpha=False) == (1, 2, 3)
|
|
assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=False) == (1, 2, 3)
|
|
|
|
assert Color((1, 2, 3)).as_rgb_tuple(alpha=True) == (1, 2, 3, 1)
|
|
assert Color((1, 2, 3, 0.3)).as_rgb_tuple(alpha=True) == (1, 2, 3, 0.3)
|
|
|
|
|
|
def test_as_hsl():
|
|
assert Color('bad').as_hsl() == 'hsl(260, 43%, 77%)'
|
|
assert Color((1, 2, 3, 0.123456)).as_hsl() == 'hsl(210, 50%, 1%, 0.12)'
|
|
assert Color('hsl(260, 43%, 77%)').as_hsl() == 'hsl(260, 43%, 77%)'
|
|
|
|
|
|
def test_as_hsl_tuple():
|
|
c = Color('016997')
|
|
h, s, l_, a = c.as_hsl_tuple(alpha=True)
|
|
assert h == pytest.approx(0.551, rel=0.01)
|
|
assert s == pytest.approx(0.986, rel=0.01)
|
|
assert l_ == pytest.approx(0.298, rel=0.01)
|
|
assert a == 1
|
|
|
|
assert c.as_hsl_tuple(alpha=False) == c.as_hsl_tuple(alpha=None) == (h, s, l_)
|
|
|
|
c = Color((3, 40, 50, 0.5))
|
|
hsla = c.as_hsl_tuple(alpha=None)
|
|
assert len(hsla) == 4
|
|
assert hsla[3] == 0.5
|
|
|
|
|
|
def test_as_hex():
|
|
assert Color((1, 2, 3)).as_hex() == '#010203'
|
|
assert Color((119, 119, 119)).as_hex() == '#777'
|
|
assert Color((119, 0, 238)).as_hex() == '#70e'
|
|
assert Color('B0B').as_hex() == '#b0b'
|
|
assert Color((1, 2, 3, 0.123456)).as_hex() == '#0102031f'
|
|
assert Color((1, 2, 3, 0.1)).as_hex() == '#0102031a'
|
|
|
|
|
|
def test_as_named():
|
|
assert Color((0, 255, 255)).as_named() == 'cyan'
|
|
assert Color('#808000').as_named() == 'olive'
|
|
assert Color('hsl(180, 100%, 50%)').as_named() == 'cyan'
|
|
|
|
assert Color((240, 248, 255)).as_named() == 'aliceblue'
|
|
with pytest.raises(ValueError) as exc_info:
|
|
Color((1, 2, 3)).as_named()
|
|
assert exc_info.value.args[0] == 'no named color found, use fallback=True, as_hex() or as_rgb()'
|
|
|
|
assert Color((1, 2, 3)).as_named(fallback=True) == '#010203'
|
|
assert Color((1, 2, 3, 0.1)).as_named(fallback=True) == '#0102031a'
|
|
|
|
|
|
def test_str_repr():
|
|
assert str(Color('red')) == 'red'
|
|
assert repr(Color('red')) == "Color('red', rgb=(255, 0, 0))"
|
|
assert str(Color((1, 2, 3))) == '#010203'
|
|
assert repr(Color((1, 2, 3))) == "Color('#010203', rgb=(1, 2, 3))"
|
|
|
|
|
|
def test_eq():
|
|
assert Color('red') == Color('red')
|
|
assert Color('red') != Color('blue')
|
|
assert Color('red') != 'red'
|
|
|
|
assert Color('red') == Color((255, 0, 0))
|
|
assert Color('red') != Color((0, 0, 255))
|
|
|
|
|
|
def test_color_hashable():
|
|
assert hash(Color('red')) != hash(Color('blue'))
|
|
assert hash(Color('red')) == hash(Color((255, 0, 0)))
|
|
assert hash(Color('red')) != hash(Color((255, 0, 0, 0.5)))
|