msgspec icon indicating copy to clipboard operation
msgspec copied to clipboard

Add `to_upper` and `to_lower` to `msgspec.Meta` for `str` objects

Open cswimr opened this issue 7 months ago • 1 comments

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

cswimr avatar Jun 23 '25 12:06 cswimr

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) ?

CharString avatar Jul 11 '25 20:07 CharString