python-attrs / python-attrs/attrs

Brainstorming: Pick types

Open
#1,125 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Thinking Typing
Dominant language
Python
Stars
5.8k
Forks
480
Avg merge
2h 15m
Merged PRs (30d)
2

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?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the proposed pick() examples and the stated Mypy plugin change; the issue does not identify repository files or tests. Done would require an agreed API plus corresponding runtime and typing behavior, so design discussion is needed before implementation.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.