Skip to content

Implement UpdateClass#85

Merged
dnwpark merged 4 commits intomainfrom
update-class
Feb 6, 2026
Merged

Implement UpdateClass#85
dnwpark merged 4 commits intomainfrom
update-class

Conversation

@dnwpark
Copy link
Contributor

@dnwpark dnwpark commented Feb 6, 2026

Lets us write things like:

type AttrsAsSets[T] = UpdateClass[
    *[Member[GetName[m], set[GetType[m]]] for m in Iter[Attrs[T]]]
]

class A:
    def __init_subclass__[T](
        cls: type[T],
    ) -> AttrsAsSets[T]:
        super().__init_subclass__()

class B(A):
    n: int

B.n will be interpretted as set[int]

Note: There is an unfortunate part of python in general, where we must wrap any for/if statements in annotations in a generic type alias.

@dnwpark dnwpark requested a review from msullivan February 6, 2026 02:45
@vercel
Copy link

vercel bot commented Feb 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
python-typemap Ready Ready Preview, Comment Feb 6, 2026 2:45am

@msullivan
Copy link
Collaborator

Note: There is an unfortunate part of python in general, where we must wrap any for/if statements in annotations in a generic type alias.

I think this is fixable by deferring the signature inspection into the inside of the GenericCallable. That's what I was getting at earlier

Though there might still be snags going the other direction

@dnwpark
Copy link
Contributor Author

dnwpark commented Feb 6, 2026

@msullivan I'm not sure that's possible during runtime. It's possible at type check time at least, but if I try to look at the annotations of something like def f[T](self, x: T) -> set[T] if IsAssignable[T, int] else T: ..., it is already collapsed to T.

@msullivan
Copy link
Collaborator

@msullivan I'm not sure that's possible during runtime. It's possible at type check time at least, but if I try to look at the annotations of something like def f[T](self, x: T) -> set[T] if IsAssignable[T, int] else T: ..., it is already collapsed to T.

Right, we'll need to do it inside the GenericCallable lambda, and we'll need to do it by calling the __annotate__ function with the actual type parameters, not via inspect, I think.

Kind of a pain; not the highest priority I suppose

Copy link
Collaborator

@msullivan msullivan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Did you test adding methods?
  • Does format_class still work with __init_subclass__ or is that the end of the world

Comment on lines +181 to +189
if (
(init_subclass := base.__dict__.get("__init_subclass__"))
and (
init_subclass_annos := getattr(
init_subclass, "__annotations__", None
)
)
and (ret_annotation := init_subclass_annos.get("return"))
):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of grabbing __annotations__ directly, we should call __annotate__ with a special environment, like we do elsewhere. That way we can arrange to put the correct type variable in at the start, and have it evaluate correctly.

... maybe; there are still snags in other places, and I'm not 100% sure we can overcome them.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could be a follow-up though

Comment on lines +602 to +604
# An annoying thing to know is that for a member classmethod of C,
# cls *should* be type[C], but if it was not explicitly annotated,
# it will be C.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't totally follow this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also confused. I have a followup that will make things more straightforward.

@dnwpark
Copy link
Contributor Author

dnwpark commented Feb 6, 2026

Added some tests for adding callables. The format class stuff worked, it was just kind of annoying to keep in sync as I was tweaking things. I've added them back in.

@dnwpark dnwpark merged commit 805335f into main Feb 6, 2026
5 checks passed
@dnwpark dnwpark deleted the update-class branch February 6, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants