sintonia/shared/tests/config/base_test.py
renovate[bot] 0296446b70
chore(deps): update dependency pydantic to >=2.5.0,<2.8 (#2981)
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [pydantic](https://togithub.com/pydantic/pydantic)
([changelog](https://docs.pydantic.dev/latest/changelog/)) |
`>=2.5.0,<2.7` -> `>=2.5.0,<2.8` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/pydantic/2.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/pydantic/2.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/pydantic/2.6.4/2.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pydantic/2.6.4/2.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>pydantic/pydantic (pydantic)</summary>

###
[`v2.7.0`](https://togithub.com/pydantic/pydantic/blob/HEAD/HISTORY.md#v270-2024-04-11)

[Compare
Source](https://togithub.com/pydantic/pydantic/compare/v2.6.4...v2.7.0)

[GitHub
release](https://togithub.com/pydantic/pydantic/releases/tag/v2.7.0)

The code released in v2.7.0 is practically identical to that of
v2.7.0b1.

##### What's Changed

##### Packaging

- Reorganize `pyproject.toml` sections by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;8899](https://togithub.com/pydantic/pydantic/pull/8899)
- Bump `pydantic-core` to `v2.18.1` by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9211](https://togithub.com/pydantic/pydantic/pull/9211)
- Adopt `jiter` `v0.2.0` by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in
[pydantic/pydantic-core#1250](https://togithub.com/pydantic/pydantic-core/pull/1250)

##### New Features

- Extract attribute docstrings from `FieldInfo.description` by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;6563](https://togithub.com/pydantic/pydantic/pull/6563)
- Add a `with_config` decorator to comply with typing spec by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;8611](https://togithub.com/pydantic/pydantic/pull/8611)
- Allow an optional separator splitting the value and unit of the result
of `ByteSize.human_readable` by
[@&#8203;jks15satoshi](https://togithub.com/jks15satoshi) in
[#&#8203;8706](https://togithub.com/pydantic/pydantic/pull/8706)
- Add generic `Secret` base type by
[@&#8203;conradogarciaberrotaran](https://togithub.com/conradogarciaberrotaran)
in [#&#8203;8519](https://togithub.com/pydantic/pydantic/pull/8519)
- Make use of `Sphinx` inventories for cross references in docs by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;8682](https://togithub.com/pydantic/pydantic/pull/8682)
- Add environment variable to disable plugins by
[@&#8203;geospackle](https://togithub.com/geospackle) in
[#&#8203;8767](https://togithub.com/pydantic/pydantic/pull/8767)
- Add support for `deprecated` fields by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;8237](https://togithub.com/pydantic/pydantic/pull/8237)
- Allow `field_serializer('*')` by
[@&#8203;ornariece](https://togithub.com/ornariece) in
[#&#8203;9001](https://togithub.com/pydantic/pydantic/pull/9001)
- Handle a case when `model_config` is defined as a model property by
[@&#8203;alexeyt101](https://togithub.com/alexeyt101) in
[#&#8203;9004](https://togithub.com/pydantic/pydantic/pull/9004)
- Update `create_model()` to support `typing.Annotated` as input by
[@&#8203;wannieman98](https://togithub.com/wannieman98) in
[#&#8203;8947](https://togithub.com/pydantic/pydantic/pull/8947)
- Add `ClickhouseDsn` support by
[@&#8203;solidguy7](https://togithub.com/solidguy7) in
[#&#8203;9062](https://togithub.com/pydantic/pydantic/pull/9062)
- Add support for `re.Pattern[str]` to `pattern` field by
[@&#8203;jag-k](https://togithub.com/jag-k) in
[#&#8203;9053](https://togithub.com/pydantic/pydantic/pull/9053)
- Support for `serialize_as_any` runtime setting by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8830](https://togithub.com/pydantic/pydantic/pull/8830)
- Add support for `typing.Self` by
[@&#8203;Youssefares](https://togithub.com/Youssefares) in
[#&#8203;9023](https://togithub.com/pydantic/pydantic/pull/9023)
- Ability to pass `context` to serialization by
[@&#8203;ornariece](https://togithub.com/ornariece) in
[#&#8203;8965](https://togithub.com/pydantic/pydantic/pull/8965)
- Add feedback widget to docs with flarelytics integration by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9129](https://togithub.com/pydantic/pydantic/pull/9129)
- Support for parsing partial JSON strings in Python by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in
[pydantic/jiter#66](https://togithub.com/pydantic/jiter/pull/66)

**Finalized in v2.7.0, rather than v2.7.0b1:**

- Add support for field level number to str coercion option by
[@&#8203;NeevCohen](https://togithub.com/NeevCohen) in
[#&#8203;9137](https://togithub.com/pydantic/pydantic/pull/9137)
- Update `warnings` parameter for serialization utilities to allow
raising a warning by
[@&#8203;Lance-Drane](https://togithub.com/Lance-Drane) in
[#&#8203;9166](https://togithub.com/pydantic/pydantic/pull/9166)

##### Changes

- Correct docs, logic for `model_construct` behavior with `extra` by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8807](https://togithub.com/pydantic/pydantic/pull/8807)
- Improve error message for improper `RootModel` subclasses by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8857](https://togithub.com/pydantic/pydantic/pull/8857)
- Use `PEP570` syntax by [@&#8203;Viicos](https://togithub.com/Viicos)
in [#&#8203;8940](https://togithub.com/pydantic/pydantic/pull/8940)
- Add `enum` and `type` to the JSON schema for single item literals by
[@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;8944](https://togithub.com/pydantic/pydantic/pull/8944)
- Deprecate `update_json_schema` internal function by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9125](https://togithub.com/pydantic/pydantic/pull/9125)
- Serialize duration to hour minute second, instead of just seconds by
[@&#8203;kakilangit](https://togithub.com/kakilangit) in
[pydantic/speedate#50](https://togithub.com/pydantic/speedate/pull/50)
- Trimming str before parsing to int and float by
[@&#8203;hungtsetse](https://togithub.com/hungtsetse) in
[pydantic/pydantic-core#1203](https://togithub.com/pydantic/pydantic-core/pull/1203)

##### Performance

- `enum` validator improvements by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in
[#&#8203;9045](https://togithub.com/pydantic/pydantic/pull/9045)
- Move `enum` validation and serialization to Rust by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in
[#&#8203;9064](https://togithub.com/pydantic/pydantic/pull/9064)
- Improve schema generation for nested dataclasses by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9114](https://togithub.com/pydantic/pydantic/pull/9114)
- Fast path for ASCII python string creation in JSON by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in in
[pydantic/jiter#72](https://togithub.com/pydantic/jiter/pull/72)
- SIMD integer and string JSON parsing on `aarch64`(**Note:** SIMD on
x86 will be implemented in a future release) by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in in
[pydantic/jiter#65](https://togithub.com/pydantic/jiter/pull/65)
- Support JSON `Cow<str>` from `jiter` by
[@&#8203;davidhewitt](https://togithub.com/davidhewitt) in
[pydantic/pydantic-core#1231](https://togithub.com/pydantic/pydantic-core/pull/1231)
- MAJOR performance improvement: update to PyO3 0.21 final by
[@&#8203;davidhewitt](https://togithub.com/davidhewitt) in
[pydantic/pydantic-core#1248](https://togithub.com/pydantic/pydantic-core/pull/1248)
- cache Python strings by
[@&#8203;samuelcolvin](https://togithub.com/samuelcolvin) in
[pydantic/pydantic-core#1240](https://togithub.com/pydantic/pydantic-core/pull/1240)

##### Fixes

- Fix strict parsing for some `Sequence`s by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8614](https://togithub.com/pydantic/pydantic/pull/8614)
- Add a check on the existence of `__qualname__` by
[@&#8203;anci3ntr0ck](https://togithub.com/anci3ntr0ck) in
[#&#8203;8642](https://togithub.com/pydantic/pydantic/pull/8642)
- Handle `__pydantic_extra__` annotation being a string or inherited by
[@&#8203;alexmojaki](https://togithub.com/alexmojaki) in
[#&#8203;8659](https://togithub.com/pydantic/pydantic/pull/8659)
- Fix json validation for `NameEmail` by
[@&#8203;Holi0317](https://togithub.com/Holi0317) in
[#&#8203;8650](https://togithub.com/pydantic/pydantic/pull/8650)
- Fix type-safety of attribute access in `BaseModel` by
[@&#8203;bluenote10](https://togithub.com/bluenote10) in
[#&#8203;8651](https://togithub.com/pydantic/pydantic/pull/8651)
- Fix bug with `mypy` plugin and `no_strict_optional = True` by
[@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;8666](https://togithub.com/pydantic/pydantic/pull/8666)
- Fix `ByteSize` error `type` change by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8681](https://togithub.com/pydantic/pydantic/pull/8681)
- Fix inheriting annotations in dataclasses by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8679](https://togithub.com/pydantic/pydantic/pull/8679)
- Fix regression in core schema generation for indirect definition
references by [@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;8702](https://togithub.com/pydantic/pydantic/pull/8702)
- Fix unsupported types bug with plain validator by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8710](https://togithub.com/pydantic/pydantic/pull/8710)
- Reverting problematic fix from 2.6 release, fixing schema building bug
by [@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8718](https://togithub.com/pydantic/pydantic/pull/8718)
- fixes `__pydantic_config__` ignored for TypeDict by
[@&#8203;13sin](https://togithub.com/13sin) in
[#&#8203;8734](https://togithub.com/pydantic/pydantic/pull/8734)
- Fix test failures with `pytest v8.0.0` due to `pytest.warns()`
starting to work inside `pytest.raises()` by
[@&#8203;mgorny](https://togithub.com/mgorny) in
[#&#8203;8678](https://togithub.com/pydantic/pydantic/pull/8678)
- Use `is_valid_field` from 1.x for `mypy` plugin by
[@&#8203;DanielNoord](https://togithub.com/DanielNoord) in
[#&#8203;8738](https://togithub.com/pydantic/pydantic/pull/8738)
- Better-support `mypy` strict equality flag by
[@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;8799](https://togithub.com/pydantic/pydantic/pull/8799)
- model_json_schema export with Annotated types misses 'required'
parameters by [@&#8203;LouisGobert](https://togithub.com/LouisGobert) in
[#&#8203;8793](https://togithub.com/pydantic/pydantic/pull/8793)
- Fix default inclusion in `FieldInfo.__repr_args__` by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8801](https://togithub.com/pydantic/pydantic/pull/8801)
- Fix resolution of forward refs in dataclass base classes that are not
present in the subclass module namespace by
[@&#8203;matsjoyce-refeyn](https://togithub.com/matsjoyce-refeyn) in
[#&#8203;8751](https://togithub.com/pydantic/pydantic/pull/8751)
- Fix `BaseModel` type annotations to be resolvable by
`typing.get_type_hints` by
[@&#8203;devmonkey22](https://togithub.com/devmonkey22) in
[#&#8203;7680](https://togithub.com/pydantic/pydantic/pull/7680)
- Fix: allow empty string aliases with `AliasGenerator` by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8810](https://togithub.com/pydantic/pydantic/pull/8810)
- Fix test along with `date` -> `datetime` timezone assumption fix by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8823](https://togithub.com/pydantic/pydantic/pull/8823)
- Fix deprecation warning with usage of `ast.Str` by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;8837](https://togithub.com/pydantic/pydantic/pull/8837)
- Add missing `deprecated` decorators by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;8877](https://togithub.com/pydantic/pydantic/pull/8877)
- Fix serialization of `NameEmail` if name includes an email address by
[@&#8203;NeevCohen](https://togithub.com/NeevCohen) in
[#&#8203;8860](https://togithub.com/pydantic/pydantic/pull/8860)
- Add information about class in error message of schema generation by
[@&#8203;Czaki](https://togithub.com/Czaki) in
[#&#8203;8917](https://togithub.com/pydantic/pydantic/pull/8917)
- Make `TypeAdapter`'s typing compatible with special forms by
[@&#8203;adriangb](https://togithub.com/adriangb) in
[#&#8203;8923](https://togithub.com/pydantic/pydantic/pull/8923)
- Fix issue with config behavior being baked into the ref schema for
`enum`s by [@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;8920](https://togithub.com/pydantic/pydantic/pull/8920)
- More helpful error re wrong `model_json_schema` usage by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8928](https://togithub.com/pydantic/pydantic/pull/8928)
- Fix nested discriminated union schema gen, pt 2 by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8932](https://togithub.com/pydantic/pydantic/pull/8932)
- Fix schema build for nested dataclasses / TypedDicts with
discriminators by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8950](https://togithub.com/pydantic/pydantic/pull/8950)
- Remove unnecessary logic for definitions schema gen with discriminated
unions by [@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;8951](https://togithub.com/pydantic/pydantic/pull/8951)
- Fix handling of optionals in `mypy` plugin by
[@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;9008](https://togithub.com/pydantic/pydantic/pull/9008)
- Fix `PlainSerializer` usage with std type constructor by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9031](https://togithub.com/pydantic/pydantic/pull/9031)
- Remove unnecessary warning for config in plugin by
[@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;9039](https://togithub.com/pydantic/pydantic/pull/9039)
- Fix default value serializing by
[@&#8203;NeevCohen](https://togithub.com/NeevCohen) in
[#&#8203;9066](https://togithub.com/pydantic/pydantic/pull/9066)
- Fix extra fields check in `Model.__getattr__()` by
[@&#8203;NeevCohen](https://togithub.com/NeevCohen) in
[#&#8203;9082](https://togithub.com/pydantic/pydantic/pull/9082)
- Fix `ClassVar` forward ref inherited from parent class by
[@&#8203;alexmojaki](https://togithub.com/alexmojaki) in
[#&#8203;9097](https://togithub.com/pydantic/pydantic/pull/9097)
- fix sequence like validator with strict `True` by
[@&#8203;andresliszt](https://togithub.com/andresliszt) in
[#&#8203;8977](https://togithub.com/pydantic/pydantic/pull/8977)
- Improve warning message when a field name shadows a field in a parent
model by [@&#8203;chan-vince](https://togithub.com/chan-vince) in
[#&#8203;9105](https://togithub.com/pydantic/pydantic/pull/9105)
- Do not warn about shadowed fields if they are not redefined in a child
class by [@&#8203;chan-vince](https://togithub.com/chan-vince) in
[#&#8203;9111](https://togithub.com/pydantic/pydantic/pull/9111)
- Fix discriminated union bug with unsubstituted type var by
[@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9124](https://togithub.com/pydantic/pydantic/pull/9124)
- Support serialization of `deque` when passed to `Sequence[blah blah
blah]` by [@&#8203;sydney-runkle](https://togithub.com/sydney-runkle) in
[#&#8203;9128](https://togithub.com/pydantic/pydantic/pull/9128)
- Init private attributes from super-types in `model_post_init` by
[@&#8203;Viicos](https://togithub.com/Viicos) in
[#&#8203;9134](https://togithub.com/pydantic/pydantic/pull/9134)
- fix `model_construct` with `validation_alias` by
[@&#8203;ornariece](https://togithub.com/ornariece) in
[#&#8203;9144](https://togithub.com/pydantic/pydantic/pull/9144)
- Ensure json-schema generator handles `Literal` `null` types by
[@&#8203;bruno-f-cruz](https://togithub.com/bruno-f-cruz) in
[#&#8203;9135](https://togithub.com/pydantic/pydantic/pull/9135)
- **Fixed in v2.7.0**: Fix allow extra generic by
[@&#8203;dmontagu](https://togithub.com/dmontagu) in
[#&#8203;9193](https://togithub.com/pydantic/pydantic/pull/9193)

##### New Contributors

- [@&#8203;hungtsetse](https://togithub.com/hungtsetse) made their first
contribution in
[#&#8203;8546](https://togithub.com/pydantic/pydantic/pull/8546)
- [@&#8203;StrawHatDrag0n](https://togithub.com/StrawHatDrag0n) made
their first contribution in
[#&#8203;8583](https://togithub.com/pydantic/pydantic/pull/8583)
- [@&#8203;anci3ntr0ck](https://togithub.com/anci3ntr0ck) made their
first contribution in
[#&#8203;8642](https://togithub.com/pydantic/pydantic/pull/8642)
- [@&#8203;Holi0317](https://togithub.com/Holi0317) made their first
contribution in
[#&#8203;8650](https://togithub.com/pydantic/pydantic/pull/8650)
- [@&#8203;bluenote10](https://togithub.com/bluenote10) made their first
contribution in
[#&#8203;8651](https://togithub.com/pydantic/pydantic/pull/8651)
- [@&#8203;ADSteele916](https://togithub.com/ADSteele916) made their
first contribution in
[#&#8203;8703](https://togithub.com/pydantic/pydantic/pull/8703)
- [@&#8203;musicinmybrain](https://togithub.com/musicinmybrain) made
their first contribution in
[#&#8203;8731](https://togithub.com/pydantic/pydantic/pull/8731)
- [@&#8203;jks15satoshi](https://togithub.com/jks15satoshi) made their
first contribution in
[#&#8203;8706](https://togithub.com/pydantic/pydantic/pull/8706)
- [@&#8203;13sin](https://togithub.com/13sin) made their first
contribution in
[#&#8203;8734](https://togithub.com/pydantic/pydantic/pull/8734)
- [@&#8203;DanielNoord](https://togithub.com/DanielNoord) made their
first contribution in
[#&#8203;8738](https://togithub.com/pydantic/pydantic/pull/8738)
-
[@&#8203;conradogarciaberrotaran](https://togithub.com/conradogarciaberrotaran)
made their first contribution in
[#&#8203;8519](https://togithub.com/pydantic/pydantic/pull/8519)
- [@&#8203;chris-griffin](https://togithub.com/chris-griffin) made their
first contribution in
[#&#8203;8775](https://togithub.com/pydantic/pydantic/pull/8775)
- [@&#8203;LouisGobert](https://togithub.com/LouisGobert) made their
first contribution in
[#&#8203;8793](https://togithub.com/pydantic/pydantic/pull/8793)
- [@&#8203;matsjoyce-refeyn](https://togithub.com/matsjoyce-refeyn) made
their first contribution in
[#&#8203;8751](https://togithub.com/pydantic/pydantic/pull/8751)
- [@&#8203;devmonkey22](https://togithub.com/devmonkey22) made their
first contribution in
[#&#8203;7680](https://togithub.com/pydantic/pydantic/pull/7680)
- [@&#8203;adamency](https://togithub.com/adamency) made their first
contribution in
[#&#8203;8847](https://togithub.com/pydantic/pydantic/pull/8847)
- [@&#8203;MamfTheKramf](https://togithub.com/MamfTheKramf) made their
first contribution in
[#&#8203;8851](https://togithub.com/pydantic/pydantic/pull/8851)
- [@&#8203;ornariece](https://togithub.com/ornariece) made their first
contribution in
[#&#8203;9001](https://togithub.com/pydantic/pydantic/pull/9001)
- [@&#8203;alexeyt101](https://togithub.com/alexeyt101) made their first
contribution in
[#&#8203;9004](https://togithub.com/pydantic/pydantic/pull/9004)
- [@&#8203;wannieman98](https://togithub.com/wannieman98) made their
first contribution in
[#&#8203;8947](https://togithub.com/pydantic/pydantic/pull/8947)
- [@&#8203;solidguy7](https://togithub.com/solidguy7) made their first
contribution in
[#&#8203;9062](https://togithub.com/pydantic/pydantic/pull/9062)
- [@&#8203;kloczek](https://togithub.com/kloczek) made their first
contribution in
[#&#8203;9047](https://togithub.com/pydantic/pydantic/pull/9047)
- [@&#8203;jag-k](https://togithub.com/jag-k) made their first
contribution in
[#&#8203;9053](https://togithub.com/pydantic/pydantic/pull/9053)
- [@&#8203;priya-gitTest](https://togithub.com/priya-gitTest) made their
first contribution in
[#&#8203;9088](https://togithub.com/pydantic/pydantic/pull/9088)
- [@&#8203;Youssefares](https://togithub.com/Youssefares) made their
first contribution in
[#&#8203;9023](https://togithub.com/pydantic/pydantic/pull/9023)
- [@&#8203;chan-vince](https://togithub.com/chan-vince) made their first
contribution in
[#&#8203;9105](https://togithub.com/pydantic/pydantic/pull/9105)
- [@&#8203;bruno-f-cruz](https://togithub.com/bruno-f-cruz) made their
first contribution in
[#&#8203;9135](https://togithub.com/pydantic/pydantic/pull/9135)
- [@&#8203;Lance-Drane](https://togithub.com/Lance-Drane) made their
first contribution in
[#&#8203;9166](https://togithub.com/pydantic/pydantic/pull/9166)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/libretime/libretime).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yNjkuMiIsInVwZGF0ZWRJblZlciI6IjM3LjI2OS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: jo <ljonas@riseup.net>
2024-04-13 14:29:58 +02:00

581 lines
18 KiB
Python

from os import environ
from pathlib import Path
from typing import List, Union
from unittest import mock
from pydantic import BaseModel, Field
from pytest import mark, raises
from typing_extensions import Annotated
from libretime_shared.config import (
AnyHttpUrlStr,
BaseConfig,
DatabaseConfig,
IcecastOutput,
RabbitMQConfig,
ShoutcastOutput,
)
AnyOutput = Annotated[
Union[IcecastOutput, ShoutcastOutput],
Field(discriminator="kind"),
]
# pylint: disable=too-few-public-methods
class FixtureConfig(BaseConfig):
public_url: AnyHttpUrlStr
api_key: str
allowed_hosts: List[str] = []
database: DatabaseConfig
rabbitmq: RabbitMQConfig = RabbitMQConfig()
outputs: List[AnyOutput]
FIXTURE_CONFIG_JSON_SCHEMA = {
"$defs": {
"AudioAAC": {
"properties": {
"channels": {
"allOf": [{"$ref": "#/$defs/AudioChannels"}],
"default": "stereo",
},
"bitrate": {"title": "Bitrate", "type": "integer"},
"format": {
"const": "aac",
"default": "aac",
"enum": ["aac"],
"title": "Format",
"type": "string",
},
},
"required": ["bitrate"],
"title": "AudioAAC",
"type": "object",
},
"AudioChannels": {
"enum": ["stereo", "mono"],
"title": "AudioChannels",
"type": "string",
},
"AudioMP3": {
"properties": {
"channels": {
"allOf": [{"$ref": "#/$defs/AudioChannels"}],
"default": "stereo",
},
"bitrate": {"title": "Bitrate", "type": "integer"},
"format": {
"const": "mp3",
"default": "mp3",
"enum": ["mp3"],
"title": "Format",
"type": "string",
},
},
"required": ["bitrate"],
"title": "AudioMP3",
"type": "object",
},
"AudioOGG": {
"properties": {
"channels": {
"allOf": [{"$ref": "#/$defs/AudioChannels"}],
"default": "stereo",
},
"bitrate": {"title": "Bitrate", "type": "integer"},
"format": {
"const": "ogg",
"default": "ogg",
"enum": ["ogg"],
"title": "Format",
"type": "string",
},
"enable_metadata": {
"anyOf": [{"type": "boolean"}, {"type": "null"}],
"default": False,
"title": "Enable Metadata",
},
},
"required": ["bitrate"],
"title": "AudioOGG",
"type": "object",
},
"AudioOpus": {
"properties": {
"channels": {
"allOf": [{"$ref": "#/$defs/AudioChannels"}],
"default": "stereo",
},
"bitrate": {"title": "Bitrate", "type": "integer"},
"format": {
"const": "opus",
"default": "opus",
"enum": ["opus"],
"title": "Format",
"type": "string",
},
},
"required": ["bitrate"],
"title": "AudioOpus",
"type": "object",
},
"DatabaseConfig": {
"properties": {
"host": {
"default": "localhost",
"title": "Host",
"type": "string",
},
"port": {"default": 5432, "title": "Port", "type": "integer"},
"name": {
"default": "libretime",
"title": "Name",
"type": "string",
},
"user": {
"default": "libretime",
"title": "User",
"type": "string",
},
"password": {
"default": "libretime",
"title": "Password",
"type": "string",
},
},
"title": "DatabaseConfig",
"type": "object",
},
"IcecastOutput": {
"properties": {
"kind": {
"const": "icecast",
"default": "icecast",
"enum": ["icecast"],
"title": "Kind",
"type": "string",
},
"enabled": {
"default": False,
"title": "Enabled",
"type": "boolean",
},
"public_url": {
"anyOf": [
{"format": "uri", "type": "string"},
{"type": "null"},
],
"default": None,
"title": "Public Url",
},
"host": {
"default": "localhost",
"title": "Host",
"type": "string",
},
"port": {"default": 8000, "title": "Port", "type": "integer"},
"mount": {"title": "Mount", "type": "string"},
"source_user": {
"default": "source",
"title": "Source User",
"type": "string",
},
"source_password": {
"title": "Source Password",
"type": "string",
},
"admin_user": {
"default": "admin",
"title": "Admin User",
"type": "string",
},
"admin_password": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Admin Password",
},
"audio": {
"discriminator": {
"mapping": {
"aac": "#/$defs/AudioAAC",
"mp3": "#/$defs/AudioMP3",
"ogg": "#/$defs/AudioOGG",
"opus": "#/$defs/AudioOpus",
},
"propertyName": "format",
},
"oneOf": [
{"$ref": "#/$defs/AudioAAC"},
{"$ref": "#/$defs/AudioMP3"},
{"$ref": "#/$defs/AudioOGG"},
{"$ref": "#/$defs/AudioOpus"},
],
"title": "Audio",
},
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Name",
},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Description",
},
"website": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Website",
},
"genre": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Genre",
},
"mobile": {
"default": False,
"title": "Mobile",
"type": "boolean",
},
},
"required": ["mount", "source_password", "audio"],
"title": "IcecastOutput",
"type": "object",
},
"RabbitMQConfig": {
"properties": {
"host": {
"default": "localhost",
"title": "Host",
"type": "string",
},
"port": {"default": 5672, "title": "Port", "type": "integer"},
"user": {
"default": "libretime",
"title": "User",
"type": "string",
},
"password": {
"default": "libretime",
"title": "Password",
"type": "string",
},
"vhost": {
"default": "/libretime",
"title": "Vhost",
"type": "string",
},
},
"title": "RabbitMQConfig",
"type": "object",
},
"ShoutcastOutput": {
"properties": {
"kind": {
"const": "shoutcast",
"default": "shoutcast",
"enum": ["shoutcast"],
"title": "Kind",
"type": "string",
},
"enabled": {
"default": False,
"title": "Enabled",
"type": "boolean",
},
"public_url": {
"anyOf": [
{"format": "uri", "type": "string"},
{"type": "null"},
],
"default": None,
"title": "Public Url",
},
"host": {
"default": "localhost",
"title": "Host",
"type": "string",
},
"port": {"default": 8000, "title": "Port", "type": "integer"},
"source_user": {
"default": "source",
"title": "Source User",
"type": "string",
},
"source_password": {
"title": "Source Password",
"type": "string",
},
"admin_user": {
"default": "admin",
"title": "Admin User",
"type": "string",
},
"admin_password": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Admin Password",
},
"audio": {
"discriminator": {
"mapping": {
"aac": "#/$defs/AudioAAC",
"mp3": "#/$defs/AudioMP3",
},
"propertyName": "format",
},
"oneOf": [
{"$ref": "#/$defs/AudioAAC"},
{"$ref": "#/$defs/AudioMP3"},
],
"title": "Audio",
},
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Name",
},
"website": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Website",
},
"genre": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"title": "Genre",
},
"mobile": {
"default": False,
"title": "Mobile",
"type": "boolean",
},
},
"required": ["source_password", "audio"],
"title": "ShoutcastOutput",
"type": "object",
},
},
"properties": {
"public_url": {"format": "uri", "title": "Public Url", "type": "string"},
"api_key": {"title": "Api Key", "type": "string"},
"allowed_hosts": {
"default": [],
"items": {"type": "string"},
"title": "Allowed Hosts",
"type": "array",
},
"database": {"$ref": "#/$defs/DatabaseConfig"},
"rabbitmq": {
"allOf": [{"$ref": "#/$defs/RabbitMQConfig"}],
"default": {
"host": "localhost",
"port": 5672,
"user": "libretime",
"password": "libretime",
"vhost": "/libretime",
},
},
"outputs": {
"items": {
"discriminator": {
"mapping": {
"icecast": "#/$defs/IcecastOutput",
"shoutcast": "#/$defs/ShoutcastOutput",
},
"propertyName": "kind",
},
"oneOf": [
{"$ref": "#/$defs/IcecastOutput"},
{"$ref": "#/$defs/ShoutcastOutput"},
],
},
"title": "Outputs",
"type": "array",
},
},
"required": ["public_url", "api_key", "database", "outputs"],
"title": "FixtureConfig",
"type": "object",
}
FIXTURE_CONFIG_RAW = """
public_url: http://libretime.example.org/
api_key: "f3bf04fc"
allowed_hosts:
- example.com
- sub.example.com
# Comment !
database:
host: "localhost"
port: 5432
ignored: "ignored"
outputs:
- enabled: true
kind: icecast
host: localhost
port: 8000
mount: main.ogg
source_password: hackme
audio:
format: ogg
bitrate: 256
"""
def test_base_config(tmp_path: Path):
config_filepath = tmp_path / "config.yml"
config_filepath.write_text(FIXTURE_CONFIG_RAW)
with mock.patch.dict(
environ,
{
"LIBRETIME_API": "invalid",
"LIBRETIME_DATABASE_PORT": "8888",
"LIBRETIME_DATABASE": "invalid",
"LIBRETIME_RABBITMQ": "invalid",
"LIBRETIME_RABBITMQ_HOST": "changed",
"LIBRETIME_OUTPUTS_0_ENABLED": "false",
"LIBRETIME_OUTPUTS_0_HOST": "changed",
"WRONGPREFIX_API_KEY": "invalid",
},
):
config = FixtureConfig(config_filepath)
assert config.model_json_schema() == FIXTURE_CONFIG_JSON_SCHEMA
assert config.public_url == "http://libretime.example.org"
assert config.api_key == "f3bf04fc"
assert config.allowed_hosts == ["example.com", "sub.example.com"]
assert config.database.host == "localhost"
assert config.database.port == 8888
assert config.rabbitmq.host == "changed"
assert config.rabbitmq.port == 5672
assert config.outputs[0].enabled is False
assert config.outputs[0].kind == "icecast"
assert config.outputs[0].host == "changed"
assert config.outputs[0].audio.format == "ogg"
# Optional model: loading default values (rabbitmq)
with mock.patch.dict(environ, {}):
config = FixtureConfig(config_filepath)
assert config.allowed_hosts == ["example.com", "sub.example.com"]
assert config.rabbitmq.host == "localhost"
assert config.rabbitmq.port == 5672
# Optional model: overriding using environment (rabbitmq)
with mock.patch.dict(
environ,
{
"LIBRETIME_RABBITMQ_HOST": "changed",
"LIBRETIME_ALLOWED_HOSTS": "example.com, changed.example.com",
},
):
config = FixtureConfig(config_filepath)
assert config.allowed_hosts == ["example.com", "changed.example.com"]
assert config.rabbitmq.host == "changed"
assert config.rabbitmq.port == 5672
# pylint: disable=too-few-public-methods
class RequiredModel(BaseModel):
api_key: str
with_default: str = "original"
# pylint: disable=too-few-public-methods
class FixtureWithRequiredSubmodelConfig(BaseConfig):
required: RequiredModel
FIXTURE_WITH_REQUIRED_SUBMODEL_CONFIG_RAW = """
required:
api_key: "test_key"
"""
def test_base_config_required_submodel(tmp_path: Path):
config_filepath = tmp_path / "config.yml"
config_filepath.write_text(FIXTURE_WITH_REQUIRED_SUBMODEL_CONFIG_RAW)
# With config file
with mock.patch.dict(environ, {}):
config = FixtureWithRequiredSubmodelConfig(config_filepath)
assert config.required.api_key == "test_key"
assert config.required.with_default == "original"
# With env variables
with mock.patch.dict(environ, {"LIBRETIME_REQUIRED_API_KEY": "test_key"}):
config = FixtureWithRequiredSubmodelConfig(None)
assert config.required.api_key == "test_key"
assert config.required.with_default == "original"
# With env variables override
with mock.patch.dict(environ, {"LIBRETIME_REQUIRED_API_KEY": "changed"}):
config = FixtureWithRequiredSubmodelConfig(config_filepath)
assert config.required.api_key == "changed"
assert config.required.with_default == "original"
# With env variables default override
with mock.patch.dict(
environ,
{
"LIBRETIME_REQUIRED_API_KEY": "changed",
"LIBRETIME_REQUIRED_WITH_DEFAULT": "changed",
},
):
config = FixtureWithRequiredSubmodelConfig(config_filepath)
assert config.required.api_key == "changed"
assert config.required.with_default == "changed"
# Raise validation error
with mock.patch.dict(environ, {}):
with raises(SystemExit):
FixtureWithRequiredSubmodelConfig(None)
def test_base_config_from_init() -> None:
class FromInitFixtureConfig(BaseConfig):
found: str
override: str
with mock.patch.dict(environ, {"LIBRETIME_OVERRIDE": "changed"}):
config = FromInitFixtureConfig(
found="changed",
override="invalid",
)
assert config.found == "changed"
assert config.override == "changed"
FIXTURE_CONFIG_RAW_MISSING = """
database:
host: "localhost"
"""
FIXTURE_CONFIG_RAW_INVALID = """
database
host: "localhost"
"""
@mark.parametrize(
"raw,exception",
[
(FIXTURE_CONFIG_RAW_INVALID, SystemExit),
(FIXTURE_CONFIG_RAW_MISSING, SystemExit),
],
)
def test_load_config_error(tmp_path: Path, raw, exception):
config_filepath = tmp_path / "config.yml"
config_filepath.write_text(raw)
with raises(exception):
with mock.patch.dict(environ, {}):
FixtureConfig(config_filepath)