# Shared field types `todays_paper_web/widgets/params.py` holds custom Pydantic *field types* — not model base classes. `View`'s and `DataSource`'s `Params` hierarchies each have their own base model ({py:class}`~todays_paper_web.widgets.view.ViewParams`, {py:class}`~todays_paper_web.widgets.datasource.DataSourceParams` — see {doc}`view`/{doc}`datasource`), deliberately *not* shared, since a widget and a data source don't actually have anything in common beyond both wanting the same `extra=ignore` config; the two model hierarchies would otherwise be joined by a base class that isn't doing anything except naming a coincidence. `Color` and `Number` below, by contrast, genuinely are shared — the same value type is meaningful as a field on either a `ViewParams` or a `DataSourceParams` subclass. ## `Color` A custom field type, not a model — a CSS color name or `#hex` code, parsed into a `webcolors.IntegerRGB`. Give a field the right default with `Field(default_factory=...)`; an unrecognized value raises rather than silently falling back to a default. ```{eval-rst} .. autoclass:: todays_paper_web.widgets.params.Color :members: ``` ## `Number` Also a custom field type: an `int` or `float`, kept as whichever type was actually given — for a `DataSource`'s YAML `params:` field that might be a whole number in one config and a decimal in another (see {doc}`../data-sources/weather`). A plain `float` field would silently turn `17` into `17.0`; `Union[int, float]` is actively unsafe in this project's Pydantic v1, since it tries `int` first and truncates a real float's fractional part. ```{eval-rst} .. autoclass:: todays_paper_web.widgets.params.Number :members: ```