Description
This is something for us to consider, and it's come up on the typing mailing list a few times.
A Pick type is a TypeScript thing. You take an existing type, and you create a new type from a subset of that type's fields. Essentially, you pick attributes from the original type.
Example from the TS docs:
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
This might be useful in a bunch of contexts, like:
- REST APIs - imagine a POST or PUT request, but it shouldn't have an ID in the model since the ID is in the URL, or autogenerated by server. You'd pick the fields you need
- Database stuff - loading projections, so you get only the fields you need
Why the additional complexity instead of just defining what you need from scratch? DRY I guess, and keeping the origin and pick models in sync automatically.
I think in runtime we can do this relatively easily. Typing-wise though it'll require a Mypy plugin change for sure.
If we do want to do this, what would the API look like?
@define
class Todo:
title: str
description: str
completed: bool
from attrs import pick, fields as f
TodoPreview = pick(Todo, f(Todo).title, f(Todo).description)
# Alternatively
TodoPreview = pick(Todo, "title", "description")
# Alternatively. This syntax feels extensible.
TodoPreview = pick(Todo, title=True, description=True)
The last syntax feels like it could be extended into the Omit
type (the opposite of pick - where you exclude types).
TodoPreview = pick(Todo, completed=False)
I think at runtime we'd just create a new type, inherinting from object
, while copying over the attributes and their defaults. So TodoPreview
is not a subclass or Todo
, or vice versa. There should be some sort of link back to the origin class at runtime via a hidden attribute, but that's about it.
Thoughts?