Add `to_upper` and `to_lower` to `msgspec.Meta` for `str` objects
Description
I have a struct that wants a str input that has whitespace stripped, is in all lowercase, is below a max length, is above a minimum length, and matches a regex pattern. This repository already has an issue for stripping whitespace through msgspec.Meta, that being #782. This is possible through __post_init__, but I don't see why this couldn't just be on Meta instead. Plus, using __post_init__ means more boilerplate. Here's an example of what this might look like in code:
from msgspec import Struct, Meta, json
from typing import Annotated
class Repository(Struct, kw_only=True):
owner: str
name: str
prefix: Annotated[str, Meta(min_length=3, max_length=30, to_lower=True, pattern=r"^[\w\-]+$")]
decoder = json.Decoder(Repository)
raw = '{"owner": "jcrist", "name": "msgspec", "prefix": "Msg-Spec"}'
repo = decoder.decode(raw)
print(repo.prefix)
# msg-spec
Versus what has to be done now (not too bad but still unnecessary boilerplate):
from msgspec import Struct, Meta, json
from typing import Annotated
class Repository(Struct, kw_only=True):
owner: str
name: str
prefix: Annotated[str, Meta(min_length=3, max_length=30, pattern=r"^[\w\-]+$")]
def __post_init__(self) -> None:
self.prefix = self.prefix.lower()
decoder = json.Decoder(Repository)
raw = '{"owner": "jcrist", "name": "msgspec", "prefix": "Msg-Spec"}'
repo = decoder.decode(raw)
print(repo.prefix)
# msg-spec
You can lower your "boilerplate" by encoding the length bounds in your pattern: r"^[\w\-]{3,30}$" or even better express what valid values are r"^[a-z0-9\-]{3,30}$" and reject invalid values.
If you do want to be lenient in what you accept, I think the modification of values to some canonical form belongs in that __post_init__.
To put it differently: what set of string operations do you expect to be able to do on values in the annotations? Should we add Meta(run_doom=True) ?